blob: 6da1150d2678ebc41512c6ac7be3888e52e7d655 [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
vinokuma926cb3e2023-03-29 11:41:06 +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 ForceDelete bool
127 // Multiservice-Fix
Naveen Sampath04696f72022-06-13 15:19:14 +0530128 UsHSIAFlowsApplied bool
129 DsHSIAFlowsApplied bool
130 UsDhcpFlowsApplied bool
131 DsDhcpFlowsApplied bool
132 IgmpFlowsApplied bool
133 Icmpv6FlowsApplied bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530134}
135
136// VoltService structure
137type VoltService struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530138 VoltServiceOper
139 Version string
vinokuma926cb3e2023-03-29 11:41:06 +0530140 VoltServiceCfg
Naveen Sampath04696f72022-06-13 15:19:14 +0530141}
142
vinokuma926cb3e2023-03-29 11:41:06 +0530143// ServiceTrigger - Service activation trigger
Naveen Sampath04696f72022-06-13 15:19:14 +0530144type ServiceTrigger int
145
146const (
vinokuma926cb3e2023-03-29 11:41:06 +0530147 // NBActivate - Service added due to NB Action
Naveen Sampath04696f72022-06-13 15:19:14 +0530148 NBActivate ServiceTrigger = 0
vinokuma926cb3e2023-03-29 11:41:06 +0530149 // ServiceVlanUpdate - Service added due to Svlan Update
Naveen Sampath04696f72022-06-13 15:19:14 +0530150 ServiceVlanUpdate ServiceTrigger = 1
151)
152
153// AppMutexes structure
154type AppMutexes struct {
155 ServiceDataMutex sync.Mutex `json:"-"`
156 VnetMutex sync.Mutex `json:"-"`
157}
158
vinokuma926cb3e2023-03-29 11:41:06 +0530159// MigrateServiceMetadata - migrate services request metadata
Naveen Sampath04696f72022-06-13 15:19:14 +0530160type MigrateServiceMetadata struct {
161 NewVnetID string
162 RequestID string
163}
164
165// AppMutex variable
166var AppMutex AppMutexes
167
168// NewVoltService for constructor for volt service
169func NewVoltService(cfg *VoltServiceCfg) *VoltService {
170 var vs VoltService
171 vs.VoltServiceCfg = *cfg
172 vs.UsHSIAFlowsApplied = false
173 vs.DsHSIAFlowsApplied = false
174 vs.DeleteInProgress = false
175 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530176 vs.IsOption82Enabled = cfg.IsOption82Enabled
Naveen Sampath04696f72022-06-13 15:19:14 +0530177 vs.MacAddr = cfg.MacAddr
178 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
179 vs.Ipv6Addr = net.ParseIP("::")
180 vs.PendingFlows = make(map[string]bool)
181 vs.AssociatedFlows = make(map[string]bool)
182 return &vs
183}
184
185// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530186func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530187 vs.ServiceLock.RLock()
188 defer vs.ServiceLock.RUnlock()
189
190 if vs.DeleteInProgress {
191 logger.Warnw(ctx, "Skipping Redis Update for Service, Service delete in progress", log.Fields{"Service": vs.Name})
192 return
193 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530194 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530195}
196
vinokuma926cb3e2023-03-29 11:41:06 +0530197// ForceWriteToDb force commit a service to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530198func (vs *VoltService) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530199 b, err := json.Marshal(vs)
200
201 if err != nil {
202 logger.Errorw(ctx, "Json Marshal Failed for Service", log.Fields{"Service": vs.Name})
203 return
204 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530205 if err1 := db.PutService(cntx, vs.Name, string(b)); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530206 logger.Errorw(ctx, "DB write oper failed for Service", log.Fields{"Service": vs.Name})
207 }
208}
209
210// isDataRateAttrPresent to check if data attribute is present
211func (vs *VoltService) isDataRateAttrPresent() bool {
212 return vs.DataRateAttr == DSLAttrEnabled
213}
214
215// DelFromDb delete a service from DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530216func (vs *VoltService) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530217 logger.Debugw(ctx, "Deleting Service from DB", log.Fields{"Name": vs.Name})
vinokuma926cb3e2023-03-29 11:41:06 +0530218 // TODO - Need to understand and delete the second call
219 // Calling twice has worked though don't know why
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530220 _ = db.DelService(cntx, vs.Name)
221 _ = db.DelService(cntx, vs.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530222}
223
224// MatchesVlans find the service that matches the VLANs. In this case it is
225// purely based on CVLAN. The CVLAN can sufficiently be used to
226// match a service
227func (vs *VoltService) MatchesVlans(vlans []of.VlanType) bool {
228 if len(vlans) != 1 {
229 return false
230 }
231
232 if vlans[0] == vs.CVlan {
233 return true
234 }
235 return false
236}
237
238// MatchesPbits allows matching a service to a pbit. This is used
239// to search for a service matching the pbits, typically to identify
240// attributes for other flows such as DHCP, IGMP, etc.
241func (vs *VoltService) MatchesPbits(pbits []of.PbitType) bool {
242 for _, pbit := range pbits {
243 for _, pb := range vs.Pbits {
244 if pb == pbit {
245 return true
246 }
247 }
248 }
249 return false
250}
251
252// IsPbitExist allows matching a service to a pbit. This is used
253// to search for a service matching the pbit
254func (vs *VoltService) IsPbitExist(pbit of.PbitType) bool {
255 for _, pb := range vs.Pbits {
256 if pb == pbit {
257 return true
258 }
259 }
260 return false
261}
262
263// AddHsiaFlows - Adds US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530264func (vs *VoltService) AddHsiaFlows(cntx context.Context) {
265 if err := vs.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530266 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
267 vs.triggerServiceFailureInd(statusCode, statusMessage)
268 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530269 if err := vs.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530270 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
271 vs.triggerServiceFailureInd(statusCode, statusMessage)
272 }
273}
274
vinokuma926cb3e2023-03-29 11:41:06 +0530275// DelHsiaFlows - Deletes US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530276func (vs *VoltService) DelHsiaFlows(cntx context.Context) {
277 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530278 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
279 vs.triggerServiceFailureInd(statusCode, statusMessage)
280 }
281
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530282 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530283 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
284 vs.triggerServiceFailureInd(statusCode, statusMessage)
285 }
286}
287
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530288func (vs *VoltService) AddMeterToDevice(cntx context.Context) error {
289 if vs.DeleteInProgress || vs.UpdateInProgress {
290 logger.Errorw(ctx, "Ignoring Meter Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
291 }
292 va := GetApplication()
293 logger.Infow(ctx, "Configuring Meters for FTTB", log.Fields{"ServiceName": vs.Name})
294 device, err := va.GetDeviceFromPort(vs.Port)
295 if err != nil {
296 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
297 return errorCodes.ErrDeviceNotFound
298 } else if device.State != controller.DeviceStateUP {
299 logger.Warnw(ctx, "Device state Down. Ignoring Meter Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
300 return nil
301 }
302 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
303 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
304 return nil
305}
306
Naveen Sampath04696f72022-06-13 15:19:14 +0530307// AddUsHsiaFlows - Add US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530308func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530309 if vs.DeleteInProgress || vs.UpdateInProgress {
310 logger.Errorw(ctx, "Ignoring US HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
311 return nil
312 }
313
314 va := GetApplication()
315 logger.Infow(ctx, "Configuring US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
316 if !vs.UsHSIAFlowsApplied || vgcRebooted {
317 device, err := va.GetDeviceFromPort(vs.Port)
318 if err != nil {
319 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
320 return errorCodes.ErrDeviceNotFound
321 } else if device.State != controller.DeviceStateUP {
322 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
323 return nil
324 }
325
326 vs.Device = device.Name
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530327 /* In case of DPU_MGMT_TRAFFIC the meters will be configured before US flow creation*/
vinokuma926cb3e2023-03-29 11:41:06 +0530328 if vs.ServiceType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530329 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
330 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
331 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530332 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
333 pBits := vs.Pbits
334
vinokuma926cb3e2023-03-29 11:41:06 +0530335 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530336 if len(vs.Pbits) == 0 {
337 pBits = append(pBits, PbitMatchNone)
338 }
339 for _, pbits := range pBits {
340 usflows, err := vs.BuildUsHsiaFlows(pbits)
341 if err != nil {
342 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
343 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
344 vs.triggerServiceFailureInd(statusCode, statusMessage)
345 continue
346 }
347 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530348 if err := vs.AddFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530349 logger.Errorw(ctx, "Error adding HSIA US flows", log.Fields{"Reason": err.Error()})
350 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
351 vs.triggerServiceFailureInd(statusCode, statusMessage)
352 }
353 }
354 vs.UsHSIAFlowsApplied = true
355 logger.Infow(ctx, "Pushed US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
356 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530357 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530358 return nil
359}
360
361// AddDsHsiaFlows - Add DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530362func (vs *VoltService) AddDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530363 if vs.DeleteInProgress {
364 logger.Errorw(ctx, "Ignoring DS HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
365 return nil
366 }
367
368 va := GetApplication()
369 logger.Infow(ctx, "Configuring DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
370 if !vs.DsHSIAFlowsApplied || vgcRebooted {
371 device, err := va.GetDeviceFromPort(vs.Port)
372 if err != nil {
373 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
374 return errorCodes.ErrDeviceNotFound
375 } else if device.State != controller.DeviceStateUP {
376 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
377 return nil
378 }
379
380 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
381 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
382
383 //If no pbits configured for service, hence add PbitNone for flows
384 if len(vs.DsRemarkPbitsMap) == 0 {
385 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
386 if err != nil {
387 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
388 return err
389 }
390 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530391 if err = vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530392 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
393 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
394 vs.triggerServiceFailureInd(statusCode, statusMessage)
395 }
396 } else {
397 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
398 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
399 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
400 if err != nil {
401 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
402 return err
403 }
404 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
405 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530406 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530407 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
408 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
409 vs.triggerServiceFailureInd(statusCode, statusMessage)
410 }
411 } else {
412 for matchPbit := range vs.DsRemarkPbitsMap {
413 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
414 if err != nil {
415 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
416 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
417 vs.triggerServiceFailureInd(statusCode, statusMessage)
418 continue
419 }
420 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530421 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530422 logger.Errorw(ctx, "Failed to Add HSIA DS flows", log.Fields{"Reason": err})
423 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
424 vs.triggerServiceFailureInd(statusCode, statusMessage)
425 }
426 }
427 }
428 }
429 vs.DsHSIAFlowsApplied = true
430 logger.Infow(ctx, "Pushed DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
431 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530432 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530433 return nil
434}
435
436// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530437func (vs *VoltService) DelUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530438 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Services": vs.Name})
439 if vs.UsHSIAFlowsApplied || vgcRebooted {
440 device, err := GetApplication().GetDeviceFromPort(vs.Port)
441 if err != nil {
442 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
443 return errorCodes.ErrDeviceNotFound
444 }
445
446 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
447 pBits := vs.Pbits
448
vinokuma926cb3e2023-03-29 11:41:06 +0530449 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530450 if len(vs.Pbits) == 0 {
451 pBits = append(pBits, PbitMatchNone)
452 }
453 for _, pbits := range pBits {
454 usflows, err := vs.BuildUsHsiaFlows(pbits)
455 if err != nil {
456 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
457 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
458 vs.triggerServiceFailureInd(statusCode, statusMessage)
459 continue
460 }
461 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530462 if err = vs.DelFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530463 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
464 vs.triggerServiceFailureInd(statusCode, statusMessage)
465 }
466 }
467 vs.UsHSIAFlowsApplied = false
468 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530469 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530470 return nil
471}
472
473// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530474func (vs *VoltService) DelDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530475 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Services": vs.Name})
476 if vs.DsHSIAFlowsApplied || vgcRebooted {
477 device, err := GetApplication().GetDeviceFromPort(vs.Port)
478 if err != nil {
479 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
480 return errorCodes.ErrDeviceNotFound
481 }
482
483 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
484 var matchPbit int
vinokuma926cb3e2023-03-29 11:41:06 +0530485 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530486 if len(vs.DsRemarkPbitsMap) == 0 {
487 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
488 if err != nil {
489 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
490 return err
491 }
492 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530493 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530494 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
495 vs.triggerServiceFailureInd(statusCode, statusMessage)
496 }
497 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
498 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
499 if err != nil {
500 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
501 return err
502 }
503 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530504 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530505 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
506 vs.triggerServiceFailureInd(statusCode, statusMessage)
507 }
508 } else {
509 for matchPbit = range vs.DsRemarkPbitsMap {
510 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
511 if err != nil {
512 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
513 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
514 vs.triggerServiceFailureInd(statusCode, statusMessage)
515 continue
516 }
517 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530518 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530519 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
520 vs.triggerServiceFailureInd(statusCode, statusMessage)
521 }
522 }
523 }
524 vs.DsHSIAFlowsApplied = false
525 }
vinokuma926cb3e2023-03-29 11:41:06 +0530526 logger.Infow(ctx, "Deleted HSIA DS flows from DB successfully", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530527 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530528 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530529 return nil
530}
531
532// BuildDsHsiaFlows build the DS HSIA flows
533// Called for add/delete HSIA flows
534func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
535 flow := &of.VoltFlow{}
536 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
537
538 // Get the out and in ports for the flows
539 device, err := GetApplication().GetDeviceFromPort(vs.Port)
540 if err != nil {
541 return nil, errorCodes.ErrDeviceNotFound
542 }
543 inport, _ := GetApplication().GetPortID(device.NniPort)
544 outport, _ := GetApplication().GetPortID(vs.Port)
545 // PortName and PortID to be used for validation of port before flow pushing
546 flow.PortID = outport
547 flow.PortName = vs.Port
548 allowTransparent := 0
549 if vs.AllowTransparent {
550 allowTransparent = 1
551 }
552
553 // initialized actnPbit to 0 for cookie genration backward compatibility.
554 var actnPbit of.PbitType
555 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
556
557 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530558 // | 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 +0530559 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
560 cookie = cookie | of.DsFlowMask
561 cookie = cookie + (valToShift << 4) + uint64(pbits)
562 return cookie
563 }
564
565 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
566 if err != nil {
567 logger.Errorw(ctx, "DS HSIA flow push failed: Invalid SvlanTpid", log.Fields{"SvlanTpid": vs.SVlanTpid, "Service": vs.Name})
568 return nil, err
569 }
570
571 // Add Table-0 flow that deals with the outer VLAN in pOLT
572 {
573 subflow1 := of.NewVoltSubFlow()
574 subflow1.SetTableID(0)
575 subflow1.SetGoToTable(1)
576 subflow1.SetInPort(inport)
577
578 if pbits != PbitMatchNone {
579 subflow1.SetMatchPbit(pbits)
580 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530581 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
582 subflow1.SetPcp(of.PbitType(remarkPbit))
583 // match & action pbits are different, set remark-pbit action
584 actnPbit = of.PbitType(remarkPbit)
585 // mask remark p-bit to 4bits
586 actnPbit = actnPbit & 0x0F
587 }
588
589 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
590 return nil, err
591 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530592 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530593 if NonZeroMacAddress(vs.MacAddr) {
594 subflow1.SetMatchDstMac(vs.MacAddr)
595 }
596 subflow1.Priority = of.HsiaFlowPriority
597 subflow1.SetMeterID(vs.DsMeterID)
598
599 /* WriteMetaData 8 Byte(uint64) usage:
600 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
601 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
602 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530603 if vs.ServiceType == FttbSubscriberTraffic {
604 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
605 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530606 subflow1.SetWriteMetadata(metadata)
607
608 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
609 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
610 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
611 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
612
613 //TODO-COMM:
614 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
615 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
616 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
617 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
618
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530619 if vs.ServiceType != FttbSubscriberTraffic {
620 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
621 subflow1.SetTableMetadata(metadata)
622 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530623 // TODO - We are using cookie as key and must come up with better cookie
624 // allocation algorithm
625 /**
626 * Cokies may clash when -
627 * on same uni-port we have two sub-service
628 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
629 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
630 * However, this p-bit re-use will not be allowed by sub-mgr.
631 */
632 if vs.VlanControl == OLTCVlanOLTSVlan {
633 /**
634 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
635 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
636 * use old cookie.
637 */
638 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
639 if vgcRebooted {
640 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
641 }
642 } else {
643 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
644 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
645 }
646
647 flow.SubFlows[subflow1.Cookie] = subflow1
648 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
649 "subflow": subflow1})
650 }
651
vinokuma926cb3e2023-03-29 11:41:06 +0530652 // Add Table-1 flow that deals with inner VLAN at the ONU
Naveen Sampath04696f72022-06-13 15:19:14 +0530653 {
654 subflow2 := of.NewVoltSubFlow()
655 subflow2.SetTableID(1)
656 subflow2.SetInPort(inport)
657 if NonZeroMacAddress(vs.MacAddr) {
658 subflow2.SetMatchDstMac(vs.MacAddr)
659 }
660
661 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
662 return nil, err
663 }
664 if pbits != PbitMatchNone {
665 subflow2.SetMatchPbit(pbits)
666 }
667
668 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
669 subflow2.SetPcp(of.PbitType(remarkPbit))
670 }
671
672 subflow2.SetOutPort(outport)
673 subflow2.SetMeterID(vs.DsMeterID)
674
675 // refer Table-0 flow generation for byte information
676 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530677 if vs.ServiceType == FttbSubscriberTraffic {
678 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
679 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530680 subflow2.SetWriteMetadata(metadata)
681
682 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
683 if util.IsNniPort(inport) {
684 metadata = uint64(outport)
685 } else {
686 // refer Table-0 flow generation for byte information
687 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
688 }
689 subflow2.SetTableMetadata(metadata)
690 // Setting of Cookie - TODO - Improve the allocation algorithm
691 if vs.VlanControl == OLTCVlanOLTSVlan {
692 /**
693 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
694 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
695 * use old cookie.
696 */
697 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
698 if vgcRebooted {
699 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
700 }
701 } else {
702 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
703 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
704 }
705
706 subflow2.Priority = of.HsiaFlowPriority
707 flow.SubFlows[subflow2.Cookie] = subflow2
708 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
709 "subflow": subflow2})
710 }
711
712 return flow, nil
713}
714
715// BuildUsHsiaFlows build the US HSIA flows
716// Called for add/delete HSIA flows
717func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
718 flow := &of.VoltFlow{}
719 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
720
721 // Get the out and in ports for the flows
722 device, err := GetApplication().GetDeviceFromPort(vs.Port)
723 if err != nil {
724 return nil, errorCodes.ErrDeviceNotFound
725 }
726 outport, _ := GetApplication().GetPortID(device.NniPort)
727 inport, _ := GetApplication().GetPortID(vs.Port)
728 // PortName and PortID to be used for validation of port before flow pushing
729 flow.PortID = inport
730 flow.PortName = vs.Port
Naveen Sampath04696f72022-06-13 15:19:14 +0530731
732 // Add Table-0 flow that deals with the inner VLAN in ONU
733 {
734 subflow1 := of.NewVoltSubFlow()
735 subflow1.SetTableID(0)
736 subflow1.SetGoToTable(1)
737 subflow1.SetInPort(inport)
738
vinokuma926cb3e2023-03-29 11:41:06 +0530739 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530740 subflow1.SetMatchPbit(vs.UsPonCTagPriority)
741 subflow1.SetPcp(vs.UsPonSTagPriority)
vinokuma926cb3e2023-03-29 11:41:06 +0530742 } else if vs.ServiceType == DpuAncpTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530743 subflow1.SetPcp(vs.UsPonSTagPriority)
744 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530745 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
746 return nil, err
747 }
748 subflow1.SetMeterID(vs.UsMeterID)
749
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530750 /* WriteMetaData 8 Byte(uint64) usage:
751 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
752 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
753 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
754 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530755 if vs.ServiceType == FttbSubscriberTraffic {
756 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
757 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530758 subflow1.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530759
Naveen Sampath04696f72022-06-13 15:19:14 +0530760 if vs.VlanControl == OLTCVlanOLTSVlan {
761 /**
762 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
763 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
764 * use old cookie.
765 */
766 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
767 if vgcRebooted {
768 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
769 }
770 } else {
771 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
772 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
773 }
774 subflow1.Priority = of.HsiaFlowPriority
775 flow.SubFlows[subflow1.Cookie] = subflow1
776 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
777 }
778
vinokuma926cb3e2023-03-29 11:41:06 +0530779 // Add Table-1 flow that deals with the outer vlan in pOLT
Naveen Sampath04696f72022-06-13 15:19:14 +0530780 {
781 subflow2 := of.NewVoltSubFlow()
782 subflow2.SetTableID(1)
783 subflow2.SetInPort(inport)
784
Naveen Sampath04696f72022-06-13 15:19:14 +0530785 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
786 return nil, err
787 }
vinokuma926cb3e2023-03-29 11:41:06 +0530788 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530789 subflow2.SetMatchSrcMac(vs.MacAddr)
790 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530791 subflow2.SetInPort(inport)
792 subflow2.SetOutPort(outport)
793 subflow2.SetMeterID(vs.UsMeterID)
794
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530795 // refer Table-0 flow generation for byte information
796 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530797 if vs.ServiceType == FttbSubscriberTraffic {
798 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
799 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530800 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530801
Naveen Sampath04696f72022-06-13 15:19:14 +0530802 if vs.VlanControl == OLTCVlanOLTSVlan {
803 /**
804 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
805 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
806 * use old cookie.
807 */
808 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
809 if vgcRebooted {
810 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
811 }
812 } else {
813 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
814 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
815 }
816 subflow2.Priority = of.HsiaFlowPriority
817
818 flow.SubFlows[subflow2.Cookie] = subflow2
819 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
820 }
821
822 return flow, nil
823}
824
825func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530826 // | 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 +0530827 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
828 cookie = cookie | of.UsFlowMask
829 cookie = cookie + (valToShift << 4) + uint64(pbits)
830 return cookie
831}
832
833// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
834// based on different Vlan Controls
835func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
836 switch vs.VlanControl {
837 case None:
838 flow.SetMatchVlan(vs.SVlan)
839 case ONUCVlanOLTSVlan:
840 flow.SetMatchVlan(vs.CVlan)
841 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
842 case OLTCVlanOLTSVlan:
843 flow.SetMatchVlan(vs.UniVlan)
844 flow.SetSetVlan(vs.CVlan)
845 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
846 case ONUCVlan:
847 flow.SetMatchVlan(vs.SVlan)
848 case OLTSVlan:
849 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
850 flow.SetMatchVlan(vs.UniVlan)
851 flow.SetSetVlan(vs.SVlan)
852 } else if vs.UniVlan != of.VlanNone {
853 flow.SetMatchVlan(vs.UniVlan)
854 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
855 } else {
856 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
857 }
858 default:
859 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
860 return errorCodes.ErrInvalidParamInRequest
861 }
862 return nil
863}
864
865// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
866// based on different Vlan Controls
867func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
868 switch vs.VlanControl {
869 case None:
870 flow.SetMatchVlan(vs.SVlan)
871 case ONUCVlanOLTSVlan:
872 flow.SetMatchVlan(vs.SVlan)
873 flow.SetPopVlan()
874 case OLTCVlanOLTSVlan:
875 flow.SetMatchVlan(vs.SVlan)
876 flow.SetPopVlan()
877 flow.SetSetVlan(vs.UniVlan)
878 case ONUCVlan:
879 flow.SetMatchVlan(vs.SVlan)
880 case OLTSVlan:
881 flow.SetMatchVlan(vs.SVlan)
882 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
883 flow.SetSetVlan(vs.UniVlan)
884 } else {
885 flow.SetPopVlan()
886 }
887 default:
888 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
889 return errorCodes.ErrInvalidParamInRequest
890 }
891 return nil
892}
893
894// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
895// based on different Vlan Controls
896func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
897 switch vs.VlanControl {
898 case None:
899 flow.SetMatchVlan(vs.SVlan)
900 case ONUCVlanOLTSVlan:
901 if vs.UniVlan != of.VlanNone {
902 flow.SetMatchVlan(vs.UniVlan)
903 flow.SetSetVlan(vs.CVlan)
904 } else {
905 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
906 }
907 case OLTCVlanOLTSVlan:
908 flow.SetMatchVlan(vs.UniVlan)
909 case ONUCVlan:
910 if vs.UniVlan != of.VlanNone {
911 flow.SetMatchVlan(vs.UniVlan)
912 flow.SetSetVlan(vs.SVlan)
913 } else {
914 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
915 }
916 case OLTSVlan:
917 flow.SetMatchVlan(vs.UniVlan)
918 default:
919 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
920 return errorCodes.ErrInvalidParamInRequest
921 }
922 return nil
923}
924
925// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
926// based on different Vlan Controls
927func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
928 switch vs.VlanControl {
929 case None:
930 flow.SetMatchVlan(vs.SVlan)
931 case ONUCVlanOLTSVlan:
932 flow.SetMatchVlan(vs.CVlan)
933 if vs.UniVlan != of.VlanNone {
934 flow.SetSetVlan(vs.UniVlan)
935 } else {
936 flow.SetPopVlan()
937 }
938 case OLTCVlanOLTSVlan:
939 flow.SetMatchVlan(vs.UniVlan)
940 case ONUCVlan:
941 flow.SetMatchVlan(vs.SVlan)
942 if vs.UniVlan != of.VlanNone {
943 flow.SetSetVlan(vs.UniVlan)
944 } else {
945 flow.SetPopVlan()
946 }
947 case OLTSVlan:
948 flow.SetMatchVlan(vs.UniVlan)
949 default:
950 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
951 return errorCodes.ErrInvalidParamInRequest
952 }
953 return nil
954}
955
956// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530957func (vs *VoltService) SvcUpInd(cntx context.Context) {
958 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530959}
960
961// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530962func (vs *VoltService) SvcDownInd(cntx context.Context) {
963 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530964}
965
966// SetIpv4Addr to set ipv4 address
967func (vs *VoltService) SetIpv4Addr(addr net.IP) {
968 vs.Ipv4Addr = addr
969}
970
971// SetIpv6Addr to set ipv6 address
972func (vs *VoltService) SetIpv6Addr(addr net.IP) {
973 vs.Ipv6Addr = addr
974}
975
976// SetMacAddr to set mac address
977func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
978 vs.MacAddr = addr
979}
980
981// ----------------------------------------------
982// VOLT Application - Related to services
983// ---------------------------------------------
984// ---------------------------------------------------------------
985// Service CRUD functions. These are exposed to the overall binary
986// to be invoked from the point where the CRUD operations are received
987// from the external entities
988
989// AddService : A service in the context of VOLT is a subscriber or service of a
990// subscriber which is uniquely identified by a combination of MAC
991// address, VLAN tags, 802.1p bits. However, in the context of the
992// current implementation, a service is an entity that is identified by a
993// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
994// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530995func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530996 var mmUs, mmDs *VoltMeter
997 var err error
998
vinokuma926cb3e2023-03-29 11:41:06 +0530999 // Take the Device lock only in case of NB add request.
Naveen Sampath04696f72022-06-13 15:19:14 +05301000 // Allow internal adds since internal add happen only under
1001 // 1. Restore Service from DB
1002 // 2. Service Migration
1003 if oper == nil {
1004 if svc := va.GetService(cfg.Name); svc != nil {
1005 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
1006 return errors.New("Service Already Exists")
1007 }
1008 }
1009
1010 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
1011 // Service doesn't exist. So create it and add to the port
1012 vs := NewVoltService(&cfg)
1013 if oper != nil {
1014 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1015 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1016 vs.Ipv4Addr = oper.Ipv4Addr
1017 vs.Ipv6Addr = oper.Ipv6Addr
1018 vs.MacLearning = cfg.MacLearning
1019 vs.PendingFlows = oper.PendingFlows
1020 vs.AssociatedFlows = oper.AssociatedFlows
1021 vs.DeleteInProgress = oper.DeleteInProgress
1022 vs.BwAvailInfo = oper.BwAvailInfo
1023 vs.Device = oper.Device
1024 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301025 // Sorting Pbit from highest
Naveen Sampath04696f72022-06-13 15:19:14 +05301026 sort.Slice(vs.Pbits, func(i, j int) bool {
1027 return vs.Pbits[i] > vs.Pbits[j]
1028 })
1029 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1030 }
1031 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1032
1033 // The bandwidth and shaper profile combined into meter
1034 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1035 vs.DsMeterID = mmDs.ID
1036 } else {
1037 return errors.New("DownStream meter profile not found")
1038 }
1039
1040 // The aggregated downstream meter profile
1041 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1042 // vs.AggDsMeterID = mmAg.ID
1043 // } else {
1044 // return errors.New("Aggregated meter profile not found")
1045 // }
1046
1047 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1048 // vs.UsMeterID = mmAg.ID
1049 // } else {
1050 // The bandwidth and shaper profile combined into meter
1051 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1052 vs.UsMeterID = mmUs.ID
1053 } else {
1054 return errors.New("Upstream meter profile not found")
1055 }
1056 //}
1057
1058 AppMutex.ServiceDataMutex.Lock()
1059 defer AppMutex.ServiceDataMutex.Unlock()
1060
1061 // Add the service to the VNET
1062 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1063 if vnet != nil {
1064 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1065 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301066 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301067 vpv.VpvLock.Unlock()
1068 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301069 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301070 }
1071 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301072 logger.Errorw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301073 return errors.New("VNET doesn't exist")
1074 }
1075
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301076 // If the device is already discovered, update the device name in service
1077 d, err := va.GetDeviceFromPort(vs.Port)
1078 if err == nil {
1079 vs.Device = d.Name
1080 }
1081
Naveen Sampath04696f72022-06-13 15:19:14 +05301082 vs.Version = database.PresentVersionMap[database.ServicePath]
1083 // Add the service to the volt application
1084 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301085 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301086
1087 if nil == oper {
Naveen Sampath04696f72022-06-13 15:19:14 +05301088 if !vs.UsHSIAFlowsApplied {
1089 vs.triggerServiceInProgressInd()
1090 }
1091
vinokuma926cb3e2023-03-29 11:41:06 +05301092 // Update meter profiles service count if service is being added from northbound
Naveen Sampath04696f72022-06-13 15:19:14 +05301093 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301094 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301095 if mmUs != nil {
1096 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301097 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301098 }
1099 //mmAg.AssociatedServices++
1100 //va.UpdateMeterProf(*mmAg)
vinokuma926cb3e2023-03-29 11:41:06 +05301101 logger.Debugw(ctx, "northbound-service-add-successful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301102 }
1103
1104 logger.Warnw(ctx, "Added Service to DB", log.Fields{"Name": vs.Name, "Port": (vs.Port), "ML": vs.MacLearning})
1105 return nil
1106}
1107
vinokuma926cb3e2023-03-29 11:41:06 +05301108// DelServiceWithPrefix - Deletes service with the provided prefix.
Naveen Sampath04696f72022-06-13 15:19:14 +05301109// Added for DT/TT usecase with sadis replica interface
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301110func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301111 va.ServiceByName.Range(func(key, value interface{}) bool {
1112 srvName := key.(string)
1113 vs := value.(*VoltService)
1114 if strings.Contains(srvName, prefix) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301115 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301116
1117 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1118 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1119 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1120
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301121 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301122 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1123 }
1124 }
1125 return true
1126 })
1127}
1128
1129// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301130func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301131 AppMutex.ServiceDataMutex.Lock()
1132 defer AppMutex.ServiceDataMutex.Unlock()
1133
1134 logger.Warnw(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
1135 var noFlowsPresent bool
1136
1137 vsIntf, ok := va.ServiceByName.Load(name)
1138 if !ok {
1139 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1140 return
1141 }
1142 vs := vsIntf.(*VoltService)
1143 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1144 if vpv == nil {
1145 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
1146 return
1147 }
1148
vinokuma926cb3e2023-03-29 11:41:06 +05301149 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301150 vs.DeleteInProgress = true
1151 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301152 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301153
1154 if len(vs.AssociatedFlows) == 0 {
1155 noFlowsPresent = true
1156 }
1157 vpv.VpvLock.Lock()
1158 defer vpv.VpvLock.Unlock()
1159
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301160 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301161
1162 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301163 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301164 }
1165 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 +05301166 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301167 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301168 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301169 }
1170
1171 // Delete the service immediately in case of Force Delete
1172 // This will be enabled when profile reconciliation happens after restore
1173 // of backedup data
1174 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301175 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301176 GetApplication().ServiceByName.Delete(vs.Name)
1177 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1178 }
1179
Naveen Sampath04696f72022-06-13 15:19:14 +05301180 if nil != newSvc {
1181 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1182 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1183 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301184
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301185 logger.Infow(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
1186
1187 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1188 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301189 if aggMeter.AssociatedServices > 0 {
1190 aggMeter.AssociatedServices--
1191 logger.Infow(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
1192 va.UpdateMeterProf(cntx, *aggMeter)
1193 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301194 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301195 }
1196 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301197 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1198 if dsMeter.AssociatedServices > 0 {
1199 dsMeter.AssociatedServices--
1200 logger.Infow(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
1201 va.UpdateMeterProf(cntx, *dsMeter)
1202 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301203 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301204 }
1205 if vs.AggDsMeterID != vs.UsMeterID {
1206 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301207 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1208 if usMeter.AssociatedServices > 0 {
1209 usMeter.AssociatedServices--
1210 logger.Infow(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
1211 va.UpdateMeterProf(cntx, *usMeter)
1212 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301213 }
1214 }
1215 }
1216
1217 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301218 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301219 }
1220
vinokuma926cb3e2023-03-29 11:41:06 +05301221 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301222 va.ServiceCounters.Delete(name)
1223 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301224 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301225 }
1226}
1227
vinokuma926cb3e2023-03-29 11:41:06 +05301228// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301229// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301230func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301231 // Using locks instead of concurrent map for PendingFlows to avoid
1232 // race condition during flow response indication processing
1233 vs.ServiceLock.Lock()
1234 defer vs.ServiceLock.Unlock()
1235
1236 for cookie := range flow.SubFlows {
1237 cookie := strconv.FormatUint(cookie, 10)
1238 fe := &FlowEvent{
1239 eType: EventTypeServiceFlowAdded,
1240 device: device.Name,
1241 cookie: cookie,
1242 eventData: vs,
1243 }
1244 device.RegisterFlowAddEvent(cookie, fe)
1245 vs.PendingFlows[cookie] = true
1246 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301247 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301248}
1249
vinokuma926cb3e2023-03-29 11:41:06 +05301250// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301251// If no more pending flows, HSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301252func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301253 if vs.DeleteInProgress {
1254 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1255 return
1256 }
1257 vs.ServiceLock.Lock()
1258
1259 if _, ok := vs.PendingFlows[cookie]; !ok {
1260 logger.Errorw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1261 vs.ServiceLock.Unlock()
1262 return
1263 }
1264
1265 delete(vs.PendingFlows, cookie)
1266 vs.AssociatedFlows[cookie] = true
1267 vs.ServiceLock.Unlock()
1268 var prevBwAvail, presentBwAvail string
1269 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1270 prevBwAvail = bwAvailInfo.PrevBw
1271 presentBwAvail = bwAvailInfo.PresentBw
1272 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301273 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301274 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301275 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301276
1277 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301278 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1279 if err != nil {
1280 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1281 return
1282 } else if device.State != controller.DeviceStateUP {
1283 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1284 return
1285 }
1286
1287 if vs.Trigger == ServiceVlanUpdate {
1288 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301289 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301290 }
1291 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1292 return
1293 }
1294 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1295}
1296
vinokuma926cb3e2023-03-29 11:41:06 +05301297// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301298// Trigger service failure indication to NB
1299func (vs *VoltService) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
1300 vs.ServiceLock.RLock()
1301
1302 if _, ok := vs.PendingFlows[cookie]; !ok {
1303 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1304 vs.ServiceLock.RUnlock()
1305 return
1306 }
1307 vs.ServiceLock.RUnlock()
1308 logger.Errorw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1309 vs.triggerServiceFailureInd(errorCode, errReason)
1310}
1311
vinokuma926cb3e2023-03-29 11:41:06 +05301312// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301313// Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301314func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301315 if !vs.ForceDelete {
1316 // Using locks instead of concurrent map for AssociatedFlows to avoid
1317 // race condition during flow response indication processing
1318 vs.ServiceLock.Lock()
1319 defer vs.ServiceLock.Unlock()
1320
1321 for cookie := range flow.SubFlows {
1322 cookie := strconv.FormatUint(cookie, 10)
1323 fe := &FlowEvent{
1324 eType: EventTypeServiceFlowRemoved,
1325 cookie: cookie,
1326 eventData: vs,
1327 }
1328 device.RegisterFlowDelEvent(cookie, fe)
1329 }
1330 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301331 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301332}
1333
vinokuma926cb3e2023-03-29 11:41:06 +05301334// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301335func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301336 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301337 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301338 GetApplication().ServiceByName.Delete(vs.Name)
1339 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1340 }
1341}
1342
vinokuma926cb3e2023-03-29 11:41:06 +05301343// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301344// If no more associated flows, DelHSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301345func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301346 // if vs.DeleteInProgress {
1347 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1348 // return
1349 // }
1350 vs.ServiceLock.Lock()
1351 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1352
1353 if _, ok := vs.AssociatedFlows[cookie]; ok {
1354 delete(vs.AssociatedFlows, cookie)
1355 } else if _, ok := vs.PendingFlows[cookie]; ok {
1356 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})
1357 } else {
1358 logger.Errorw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
1359 }
1360
1361 vs.ServiceLock.Unlock()
1362
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301363 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301364
1365 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301366 device := GetApplication().GetDevice(vs.Device)
1367 if device == nil {
1368 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1369 return
1370 } else if device.State != controller.DeviceStateUP {
1371 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1372 return
1373 }
1374
1375 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301376 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301377 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301378 return
1379 }
1380 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 +05301381 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301382
1383 return
1384 }
1385 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1386}
1387
vinokuma926cb3e2023-03-29 11:41:06 +05301388// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301389// Trigger service failure indication to NB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301390func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301391 vs.ServiceLock.RLock()
1392
1393 if _, ok := vs.AssociatedFlows[cookie]; !ok {
1394 logger.Errorw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1395 vs.ServiceLock.RUnlock()
1396 return
1397 }
1398 if vs.DeleteInProgress {
1399 delete(vs.AssociatedFlows, cookie)
1400 }
1401 vs.ServiceLock.RUnlock()
1402 logger.Errorw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1403
1404 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301405 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301406}
1407
1408func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
1409 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1410 if err != nil {
1411 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1412 return
1413 } else if device.State != controller.DeviceStateUP {
1414 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1415 return
1416 }
1417}
1418
1419// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301420func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301421 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301422 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301423 for _, vs := range vss {
1424 b, ok := vs.Value.([]byte)
1425 if !ok {
1426 logger.Warn(ctx, "The value type is not []byte")
1427 continue
1428 }
1429 var vvs VoltService
1430 err := json.Unmarshal(b, &vvs)
1431 if err != nil {
1432 logger.Warn(ctx, "Unmarshal of VNET failed")
1433 continue
1434 }
1435 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301436 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301437 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1438 }
1439
1440 if vvs.VoltServiceOper.DeleteInProgress {
1441 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1442 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1443 }
1444 }
1445}
1446
1447// GetService to get service
1448func (va *VoltApplication) GetService(name string) *VoltService {
1449 if vs, ok := va.ServiceByName.Load(name); ok {
1450 return vs.(*VoltService)
1451 }
1452 return nil
1453}
1454
1455// GetCircuitID to get circuit id
1456func (vs *VoltService) GetCircuitID() []byte {
1457 return []byte(vs.CircuitID)
1458}
1459
1460// GetRemoteID to get remote id
1461func (vs *VoltService) GetRemoteID() []byte {
1462 return []byte(vs.RemoteID)
1463}
1464
1465// IPAssigned to check if ip is assigned
1466func (vs *VoltService) IPAssigned() bool {
1467 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1468 return true
1469 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1470 return true
1471 }
1472 return false
1473}
1474
1475// GetServiceNameFromCookie to get service name from cookie
1476func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
Naveen Sampath04696f72022-06-13 15:19:14 +05301477 var vlan uint64
1478 vlanControl := (tableMetadata >> 32) & 0xF
1479
1480 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1481 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1482 vlan = (tableMetadata >> 16) & 0xFFFF
1483 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301484 // Fetching CVlan for other vlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301485 vlan = cookie >> 52
1486 }
1487 logger.Infow(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
1488 var vlans []of.VlanType
1489 vlans = append(vlans, of.VlanType(vlan))
1490 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1491 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301492 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301493 } else {
1494 logger.Errorw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
1495 }
1496 return service
1497}
1498
vinokuma926cb3e2023-03-29 11:41:06 +05301499// MigrateServicesReqStatus - update vnet request status
Naveen Sampath04696f72022-06-13 15:19:14 +05301500type MigrateServicesReqStatus string
1501
1502const (
vinokuma926cb3e2023-03-29 11:41:06 +05301503 // MigrateSrvsReqInit constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301504 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
vinokuma926cb3e2023-03-29 11:41:06 +05301505 // MigrateSrvsReqDeactTriggered constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301506 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
vinokuma926cb3e2023-03-29 11:41:06 +05301507 // MigrateSrvsReqCompleted constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301508 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1509)
1510
vinokuma926cb3e2023-03-29 11:41:06 +05301511// MigrateServicesRequest - update vnet request params
Naveen Sampath04696f72022-06-13 15:19:14 +05301512type MigrateServicesRequest struct {
1513 ID string
1514 OldVnetID string
1515 NewVnetID string
1516 ServicesList map[string]bool
1517 DeviceID string
1518 Status MigrateServicesReqStatus
1519 MigrateServicesLock sync.RWMutex
1520}
1521
1522func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
Naveen Sampath04696f72022-06-13 15:19:14 +05301523 var msr MigrateServicesRequest
1524 msr.OldVnetID = oldVnetID
1525 msr.NewVnetID = newVnetID
1526 msr.ID = id
1527 msr.ServicesList = serviceMap
1528 msr.DeviceID = deviceID
1529 msr.Status = MigrateSrvsReqInit
1530 return &msr
1531}
1532
vinokuma926cb3e2023-03-29 11:41:06 +05301533// GetMsrKey - generates migrate service request key
Naveen Sampath04696f72022-06-13 15:19:14 +05301534func (msr *MigrateServicesRequest) GetMsrKey() string {
1535 return msr.OldVnetID + "-" + msr.ID
1536}
1537
1538// //isRequestComplete - return if all request has been processed and completed
1539// // RequestProcessed indicates that all the profile de-activation has been triggered
1540// // And the associated profiles indicates the profiles awaiting results
1541// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1542// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1543// return (len(edr.AssociatedProfiles) == 0)
1544// }
1545
vinokuma926cb3e2023-03-29 11:41:06 +05301546// WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301547func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301548 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)})
1549 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301550 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301551 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301552 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301553 }
1554 }
1555}
1556
vinokuma926cb3e2023-03-29 11:41:06 +05301557// MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301558func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301559 logger.Warnw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
1560 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
1561 return errors.New("Old Vnet Id not found")
1562 }
1563 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
1564 return errors.New("New Vnet Id not found")
1565 }
1566
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301567 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301568 if d == nil {
1569 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1570 return errorCodes.ErrDeviceNotFound
1571 }
1572
1573 serviceMap := make(map[string]bool)
1574
1575 for _, service := range serviceList {
1576 serviceMap[service] = false
1577 }
1578 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301579 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301580
1581 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301582 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301583 return nil
1584}
1585
vinokuma926cb3e2023-03-29 11:41:06 +05301586// ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301587func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301588 va := GetApplication()
1589 for srv, processed := range msr.ServicesList {
vinokuma926cb3e2023-03-29 11:41:06 +05301590 // Indicates new service is already created and only deletion of old one is pending
Naveen Sampath04696f72022-06-13 15:19:14 +05301591 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301592 va.DelService(cntx, srv, true, nil, true)
1593 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301594 continue
1595 }
1596
1597 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1598 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1599 vs := vsIntf.(*VoltService)
1600 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1601 if vpv == nil {
1602 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
1603 continue
1604 }
1605 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1606 vpv.Blocked = true
1607
1608 // setDeactTrigger := func(key, value interface{}) bool {
1609 // vs := value.(*VoltService)
1610 vs.ServiceLock.Lock()
1611 vs.UpdateInProgress = true
1612 metadata := &MigrateServiceMetadata{
1613 NewVnetID: msr.NewVnetID,
1614 RequestID: msr.ID,
1615 }
1616 vs.Metadata = metadata
1617 vs.ServiceLock.Unlock()
1618
vinokuma926cb3e2023-03-29 11:41:06 +05301619 // vpv flows will be removed when last service is removed from it and
Naveen Sampath04696f72022-06-13 15:19:14 +05301620 // new vpv flows will be installed when new service is added
1621 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301622 vpv.DelTrapFlows(cntx)
1623 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301624 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301625 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301626 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301627 }
1628 } else {
1629 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1630 }
1631 }
1632}
1633
vinokuma926cb3e2023-03-29 11:41:06 +05301634// AddMigratingServices - store msr info to device obj
Naveen Sampath04696f72022-06-13 15:19:14 +05301635func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301636 var msrMap *util.ConcurrentMap
1637 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1638 msrMap = util.NewConcurrentMap()
1639 } else {
1640 msrMap = msrMapIntf.(*util.ConcurrentMap)
1641 }
1642
1643 msrMap.Set(msr.ID, msr)
1644 logger.Infow(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
1645
1646 d.MigratingServices.Set(msr.OldVnetID, msrMap)
1647 logger.Infow(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301648}
1649
vinokuma926cb3e2023-03-29 11:41:06 +05301650// getMigrateServicesRequest - fetches msr info from device
Naveen Sampath04696f72022-06-13 15:19:14 +05301651func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
1652 if vd := va.GetDevice(deviceID); vd != nil {
1653 logger.Infow(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
1654 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1655 msrList := msrListIntf.(*util.ConcurrentMap)
1656 logger.Infow(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
1657 if msrObj, ok := msrList.Get(requestID); ok {
1658 return msrObj.(*MigrateServicesRequest)
1659 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301660 }
1661 }
1662 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
1663 return nil
1664}
1665
vinokuma926cb3e2023-03-29 11:41:06 +05301666// updateMigrateServicesRequest - Updates the device with updated msr
Naveen Sampath04696f72022-06-13 15:19:14 +05301667func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
1668 if vd := va.GetDevice(deviceID); vd != nil {
1669 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1670 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1671 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1672 }
1673 }
1674 }
1675}
1676
vinokuma926cb3e2023-03-29 11:41:06 +05301677// updateVnetProfile - Called on flow process completion
1678// Removes old service and creates new VPV & service with updated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301679func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301680 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 +05301681
1682 nvs := VoltService{}
1683 nvs.VoltServiceCfg = vs.VoltServiceCfg
1684 nvs.Device = vs.Device
1685 nvs.Ipv4Addr = vs.Ipv4Addr
1686 nvs.Ipv6Addr = vs.Ipv6Addr
1687 nvs.UsMeterID = vs.UsMeterID
1688 nvs.DsMeterID = vs.DsMeterID
1689 nvs.AggDsMeterID = vs.AggDsMeterID
1690 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1691 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1692 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1693 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1694 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1695 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1696 nvs.PendingFlows = vs.PendingFlows
1697 nvs.AssociatedFlows = vs.AssociatedFlows
1698 nvs.DeleteInProgress = vs.DeleteInProgress
1699 nvs.ForceDelete = vs.ForceDelete
1700 nvs.BwAvailInfo = vs.BwAvailInfo
1701 nvs.UpdateInProgress = vs.UpdateInProgress
1702
1703 if nvs.DeleteInProgress {
1704 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1705 return
1706 }
1707
1708 metadata := vs.Metadata.(*MigrateServiceMetadata)
1709 oldVnetID := vs.VnetID
Naveen Sampath04696f72022-06-13 15:19:14 +05301710 oldSrvName := vs.Name
1711
1712 if metadata == nil || metadata.NewVnetID == "" {
1713 logger.Errorw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
1714 return
1715 }
1716
vinokuma926cb3e2023-03-29 11:41:06 +05301717 nvs.VnetID = metadata.NewVnetID
1718 id := metadata.RequestID
1719
1720 // First add the new service and then only delete the old service
Naveen Sampath04696f72022-06-13 15:19:14 +05301721 // Since if post del service in case of pod crash or reboot, the service data will be lost
1722 va := GetApplication()
1723 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1724 vnets := strings.Split(metadata.NewVnetID, "-")
1725 svlan, _ := strconv.Atoi(vnets[0])
1726 nvs.SVlan = of.VlanType(svlan)
1727 nvs.UpdateInProgress = false
1728 nvs.Metadata = nil
1729 nvs.Trigger = ServiceVlanUpdate
1730
1731 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1732 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1733 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1734
vinokuma926cb3e2023-03-29 11:41:06 +05301735 // TODO:Nav Pass a copy, not the pointer
Naveen Sampath04696f72022-06-13 15:19:14 +05301736 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 +05301737 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301738 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1739 }
1740 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1741
1742 msr.ServicesList[oldSrvName] = true
1743 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301744 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301745
1746 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 +05301747 va.DelService(cntx, oldSrvName, true, nil, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301748 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 +05301749 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301750}
1751
vinokuma926cb3e2023-03-29 11:41:06 +05301752// serviceMigrated - called on successful service updation
Naveen Sampath04696f72022-06-13 15:19:14 +05301753// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301754func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301755 msr.MigrateServicesLock.Lock()
1756 defer msr.MigrateServicesLock.Unlock()
1757
1758 delete(msr.ServicesList, serviceName)
1759
1760 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301761 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301762 return
1763 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301764 msr.WriteToDB(cntx)
vinokuma926cb3e2023-03-29 11:41:06 +05301765 // TODO:Nav - Need for any Response to SubMgr?
Naveen Sampath04696f72022-06-13 15:19:14 +05301766}
1767
vinokuma926cb3e2023-03-29 11:41:06 +05301768// TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301769func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1770 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301771}
1772
vinokuma926cb3e2023-03-29 11:41:06 +05301773// FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301774func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301775 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301776 for _, msr := range msrList {
1777 b, ok := msr.Value.([]byte)
1778 if !ok {
1779 logger.Warn(ctx, "The value type is not []byte")
1780 continue
1781 }
1782 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301783 msrAction(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301784 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 +05301785 }
1786}
1787
1788// createMigrateServicesFromString to create Service from string
1789func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
1790 var msr MigrateServicesRequest
1791 if err := json.Unmarshal(b, &msr); err == nil {
1792 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301793 } else {
1794 logger.Warn(ctx, "Unmarshal failed")
1795 }
1796 return &msr
1797}
1798
vinokuma926cb3e2023-03-29 11:41:06 +05301799// storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301800func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301801 d := GetApplication().GetDevice(msr.DeviceID)
1802 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301803 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301804}
1805
vinokuma926cb3e2023-03-29 11:41:06 +05301806// forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301807func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301808 for srv := range msr.ServicesList {
1809 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301810 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301811 }
1812 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301813 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301814}
1815
vinokuma926cb3e2023-03-29 11:41:06 +05301816// nolint: gocyclo
1817// DeepEqualServicecfg - checks if the given service cfgs are same
Naveen Sampath04696f72022-06-13 15:19:14 +05301818func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1819 if nvs.Name != evs.Name {
1820 return false
1821 }
1822 if nvs.UniVlan != evs.UniVlan {
1823 return false
1824 }
1825 if nvs.CVlan != evs.CVlan {
1826 return false
1827 }
1828 if nvs.SVlan != evs.SVlan {
1829 return false
1830 }
1831 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1832 return false
1833 }
1834 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1835 return false
1836 }
1837 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1838 return false
1839 }
1840 if nvs.TechProfileID != evs.TechProfileID {
1841 return false
1842 }
1843 if nvs.CircuitID != evs.CircuitID {
1844 return false
1845 }
1846 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1847 return false
1848 }
1849 if nvs.Port != evs.Port {
1850 return false
1851 }
1852 if nvs.PonPort != evs.PonPort {
1853 return false
1854 }
1855 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1856 return false
1857 }
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05301858 if nvs.IsOption82Enabled != evs.IsOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +05301859 return false
1860 }
1861 if nvs.IgmpEnabled != evs.IgmpEnabled {
1862 return false
1863 }
1864 if nvs.McastService != evs.McastService {
1865 return false
1866 }
1867 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1868 return false
1869 }
1870 if nvs.UsMeterProfile != evs.UsMeterProfile {
1871 return false
1872 }
1873 if nvs.DsMeterProfile != evs.DsMeterProfile {
1874 return false
1875 }
1876 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
1877 return false
1878 }
1879 if nvs.VnetID != evs.VnetID {
1880 return false
1881 }
1882 if nvs.MvlanProfileName != evs.MvlanProfileName {
1883 return false
1884 }
1885 if nvs.RemoteIDType != evs.RemoteIDType {
1886 return false
1887 }
1888 if nvs.SchedID != evs.SchedID {
1889 return false
1890 }
1891 if nvs.AllowTransparent != evs.AllowTransparent {
1892 return false
1893 }
1894 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
1895 return false
1896 }
1897 if nvs.DataRateAttr != evs.DataRateAttr {
1898 return false
1899 }
1900 if nvs.MinDataRateUs != evs.MinDataRateUs {
1901 return false
1902 }
1903 if nvs.MinDataRateDs != evs.MinDataRateDs {
1904 return false
1905 }
1906 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
1907 return false
1908 }
1909 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
1910 return false
1911 }
1912
1913 return true
1914}
1915
vinokuma926cb3e2023-03-29 11:41:06 +05301916// TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301917func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
vinokuma926cb3e2023-03-29 11:41:06 +05301918 // Clear the Flows flag if already set
1919 // This case happens only in case of some race condition
Naveen Sampath04696f72022-06-13 15:19:14 +05301920 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301921 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301922 logger.Errorw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1923 }
1924 }
1925
1926 if vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301927 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301928 logger.Errorw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1929 }
1930 }
1931
1932 vs.ServiceLock.Lock()
1933 cookieList := []uint64{}
1934 for cookie := range vs.AssociatedFlows {
1935 cookieList = append(cookieList, convertToUInt64(cookie))
1936 }
1937 vs.ServiceLock.Unlock()
1938
1939 if len(cookieList) == 0 {
1940 return false
1941 }
1942
vinokuma926cb3e2023-03-29 11:41:06 +05301943 // Trigger Flow Delete
Naveen Sampath04696f72022-06-13 15:19:14 +05301944 for _, cookie := range cookieList {
1945 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
1946 flow := &of.VoltFlow{}
1947 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1948 subFlow := of.NewVoltSubFlow()
1949 subFlow.Cookie = cookie
1950 flow.SubFlows[cookie] = subFlow
1951 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301952 if err := vs.DelFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301953 logger.Errorw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
1954 }
1955 }
1956 }
1957 return true
1958}
1959
vinokuma926cb3e2023-03-29 11:41:06 +05301960// triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
Naveen Sampath04696f72022-06-13 15:19:14 +05301961func (vs *VoltService) triggerServiceInProgressInd() {
1962}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301963
vinokuma926cb3e2023-03-29 11:41:06 +05301964// JSONMarshal wrapper function for json Marshal VoltService
1965func (vs *VoltService) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301966 return json.Marshal(VoltService{
1967 VoltServiceCfg: vs.VoltServiceCfg,
1968 VoltServiceOper: VoltServiceOper{
1969 Device: vs.VoltServiceOper.Device,
1970 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
1971 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
1972 UsMeterID: vs.VoltServiceOper.UsMeterID,
1973 DsMeterID: vs.VoltServiceOper.DsMeterID,
1974 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
1975 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
1976 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
1977 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
1978 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
1979 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
1980 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
1981 PendingFlows: vs.VoltServiceOper.PendingFlows,
1982 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
1983 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
1984 ForceDelete: vs.VoltServiceOper.ForceDelete,
1985 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
1986 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
1987 Metadata: vs.VoltServiceOper.Metadata,
1988 },
1989 })
1990}
Tinoj Josephec742f62022-09-29 19:11:10 +05301991
1992// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301993func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05301994 var svcList []*VoltService
1995 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
1996 va.ServiceByName.Range(func(key, value interface{}) bool {
1997 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301998 if len(deviceID) > 0 {
1999 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302000 if deviceID == vs.Device && portNo == vs.Port {
2001 svcList = append(svcList, vs)
2002 }
2003 } else {
2004 if deviceID == vs.Device {
2005 svcList = append(svcList, vs)
2006 }
2007 }
2008 } else {
2009 svcList = append(svcList, vs)
2010 }
2011 return true
2012 })
2013 return svcList, nil
2014}
2015
2016// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302017func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302018 logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302019 device, err := va.GetDeviceFromPort(portNo)
2020 if err != nil {
2021 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2022 return errorCodes.ErrPortNotFound
2023 }
2024 // If device id is not provided check only port number
2025 if deviceID == DeviceAny {
2026 deviceID = device.Name
2027 } else if deviceID != device.Name {
2028 logger.Errorw(ctx, "Wrong Device ID", log.Fields{"Device": deviceID, "Port": portNo})
2029 return errorCodes.ErrDeviceNotFound
2030 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302031 va.ServiceByName.Range(func(key, value interface{}) bool {
2032 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302033 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302034 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302035 logger.Infow(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302036 return true
2037 }
2038 if portNo == vs.Port && !vs.IsActivated {
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302039 p := device.GetPort(vs.Port)
Tinoj Josephec742f62022-09-29 19:11:10 +05302040 if p == nil {
2041 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2042 return true
2043 }
2044 logger.Infow(ctx, "Service Activate", log.Fields{"Name": vs.Name})
2045 vs.IsActivated = true
2046 va.ServiceByName.Store(vs.Name, vs)
2047 vs.WriteToDb(cntx)
2048 // If port is already up send indication to vpv
2049 if p.State == PortStateUp {
2050 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2051 // PortUp call initiates flow addition
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302052 vpv.PortUpInd(cntx, device, portNo)
Tinoj Josephec742f62022-09-29 19:11:10 +05302053 } else {
2054 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2055 }
2056 }
2057 }
2058 return true
2059 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302060 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302061}
2062
2063// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302064func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302065 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2066 va.ServiceByName.Range(func(key, value interface{}) bool {
2067 vs := value.(*VoltService)
2068 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302069 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2070 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
vinokuma926cb3e2023-03-29 11:41:06 +05302071 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 +05302072 return true
2073 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302074 if portNo == vs.Port && vs.IsActivated {
Tinoj Josephec742f62022-09-29 19:11:10 +05302075 vs.IsActivated = false
2076 va.ServiceByName.Store(vs.Name, vs)
2077 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302078 device, err := va.GetDeviceFromPort(portNo)
2079 if err != nil {
2080 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2081 // So no error is returned
2082 logger.Infow(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2083 return true
2084 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302085 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302086 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302087 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2088 // Port down call internally deletes all the flows
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302089 vpv.PortDownInd(cntx, deviceID, portNo, true)
Tinoj Josephec742f62022-09-29 19:11:10 +05302090 if vpv.IgmpEnabled {
2091 va.ReceiverDownInd(cntx, deviceID, portNo)
2092 }
2093 } else {
2094 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2095 }
2096 }
2097 }
2098 return true
2099 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302100 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302101}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302102
vinokuma926cb3e2023-03-29 11:41:06 +05302103// GetServicePbit to get first set bit in the pbit map
2104// returns -1 : If configured to match on all pbits
2105// returns 8 : If no pbits are configured
2106// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302107func (vs *VoltService) GetServicePbit() int {
2108 if vs.IsPbitExist(of.PbitMatchAll) {
2109 return -1
2110 }
vinokuma926cb3e2023-03-29 11:41:06 +05302111 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302112 if vs.IsPbitExist(of.PbitType(pbit)) {
2113 return pbit
2114 }
2115 }
2116 return int(of.PbitMatchNone)
2117}