blob: e6e81c38ec5591b4da479f2e94e288c224642658 [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
101 IsOption82Disabled bool
102 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")
176
177 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)
603 subflow1.SetWriteMetadata(metadata)
604
605 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
606 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
607 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
608 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
609
610 //TODO-COMM:
611 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
612 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
613 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
614 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
615
616 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
617 subflow1.SetTableMetadata(metadata)
618 // TODO - We are using cookie as key and must come up with better cookie
619 // allocation algorithm
620 /**
621 * Cokies may clash when -
622 * on same uni-port we have two sub-service
623 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
624 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
625 * However, this p-bit re-use will not be allowed by sub-mgr.
626 */
627 if vs.VlanControl == OLTCVlanOLTSVlan {
628 /**
629 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
630 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
631 * use old cookie.
632 */
633 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
634 if vgcRebooted {
635 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
636 }
637 } else {
638 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
639 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
640 }
641
642 flow.SubFlows[subflow1.Cookie] = subflow1
643 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
644 "subflow": subflow1})
645 }
646
vinokuma926cb3e2023-03-29 11:41:06 +0530647 // Add Table-1 flow that deals with inner VLAN at the ONU
Naveen Sampath04696f72022-06-13 15:19:14 +0530648 {
649 subflow2 := of.NewVoltSubFlow()
650 subflow2.SetTableID(1)
651 subflow2.SetInPort(inport)
652 if NonZeroMacAddress(vs.MacAddr) {
653 subflow2.SetMatchDstMac(vs.MacAddr)
654 }
655
656 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
657 return nil, err
658 }
659 if pbits != PbitMatchNone {
660 subflow2.SetMatchPbit(pbits)
661 }
662
663 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
664 subflow2.SetPcp(of.PbitType(remarkPbit))
665 }
666
667 subflow2.SetOutPort(outport)
668 subflow2.SetMeterID(vs.DsMeterID)
669
670 // refer Table-0 flow generation for byte information
671 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
672 subflow2.SetWriteMetadata(metadata)
673
674 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
675 if util.IsNniPort(inport) {
676 metadata = uint64(outport)
677 } else {
678 // refer Table-0 flow generation for byte information
679 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
680 }
681 subflow2.SetTableMetadata(metadata)
682 // Setting of Cookie - TODO - Improve the allocation algorithm
683 if vs.VlanControl == OLTCVlanOLTSVlan {
684 /**
685 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
686 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
687 * use old cookie.
688 */
689 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
690 if vgcRebooted {
691 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
692 }
693 } else {
694 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
695 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
696 }
697
698 subflow2.Priority = of.HsiaFlowPriority
699 flow.SubFlows[subflow2.Cookie] = subflow2
700 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
701 "subflow": subflow2})
702 }
703
704 return flow, nil
705}
706
707// BuildUsHsiaFlows build the US HSIA flows
708// Called for add/delete HSIA flows
709func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
710 flow := &of.VoltFlow{}
711 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
712
713 // Get the out and in ports for the flows
714 device, err := GetApplication().GetDeviceFromPort(vs.Port)
715 if err != nil {
716 return nil, errorCodes.ErrDeviceNotFound
717 }
718 outport, _ := GetApplication().GetPortID(device.NniPort)
719 inport, _ := GetApplication().GetPortID(vs.Port)
720 // PortName and PortID to be used for validation of port before flow pushing
721 flow.PortID = inport
722 flow.PortName = vs.Port
Naveen Sampath04696f72022-06-13 15:19:14 +0530723
724 // Add Table-0 flow that deals with the inner VLAN in ONU
725 {
726 subflow1 := of.NewVoltSubFlow()
727 subflow1.SetTableID(0)
728 subflow1.SetGoToTable(1)
729 subflow1.SetInPort(inport)
730
vinokuma926cb3e2023-03-29 11:41:06 +0530731 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530732 subflow1.SetMatchPbit(vs.UsPonCTagPriority)
733 subflow1.SetPcp(vs.UsPonSTagPriority)
vinokuma926cb3e2023-03-29 11:41:06 +0530734 } else if vs.ServiceType == DpuAncpTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530735 subflow1.SetPcp(vs.UsPonSTagPriority)
736 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530737 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
738 return nil, err
739 }
740 subflow1.SetMeterID(vs.UsMeterID)
741
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530742 /* WriteMetaData 8 Byte(uint64) usage:
743 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
744 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
745 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
746 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
747 subflow1.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530748
Naveen Sampath04696f72022-06-13 15:19:14 +0530749 if vs.VlanControl == OLTCVlanOLTSVlan {
750 /**
751 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
752 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
753 * use old cookie.
754 */
755 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
756 if vgcRebooted {
757 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
758 }
759 } else {
760 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
761 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
762 }
763 subflow1.Priority = of.HsiaFlowPriority
764 flow.SubFlows[subflow1.Cookie] = subflow1
765 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
766 }
767
vinokuma926cb3e2023-03-29 11:41:06 +0530768 // Add Table-1 flow that deals with the outer vlan in pOLT
Naveen Sampath04696f72022-06-13 15:19:14 +0530769 {
770 subflow2 := of.NewVoltSubFlow()
771 subflow2.SetTableID(1)
772 subflow2.SetInPort(inport)
773
Naveen Sampath04696f72022-06-13 15:19:14 +0530774 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
775 return nil, err
776 }
vinokuma926cb3e2023-03-29 11:41:06 +0530777 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530778 subflow2.SetMatchSrcMac(vs.MacAddr)
779 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530780 subflow2.SetInPort(inport)
781 subflow2.SetOutPort(outport)
782 subflow2.SetMeterID(vs.UsMeterID)
783
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530784 // refer Table-0 flow generation for byte information
785 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
786 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530787
Naveen Sampath04696f72022-06-13 15:19:14 +0530788 if vs.VlanControl == OLTCVlanOLTSVlan {
789 /**
790 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
791 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
792 * use old cookie.
793 */
794 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
795 if vgcRebooted {
796 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
797 }
798 } else {
799 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
800 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
801 }
802 subflow2.Priority = of.HsiaFlowPriority
803
804 flow.SubFlows[subflow2.Cookie] = subflow2
805 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
806 }
807
808 return flow, nil
809}
810
811func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530812 // | 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 +0530813 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
814 cookie = cookie | of.UsFlowMask
815 cookie = cookie + (valToShift << 4) + uint64(pbits)
816 return cookie
817}
818
819// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
820// based on different Vlan Controls
821func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
822 switch vs.VlanControl {
823 case None:
824 flow.SetMatchVlan(vs.SVlan)
825 case ONUCVlanOLTSVlan:
826 flow.SetMatchVlan(vs.CVlan)
827 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
828 case OLTCVlanOLTSVlan:
829 flow.SetMatchVlan(vs.UniVlan)
830 flow.SetSetVlan(vs.CVlan)
831 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
832 case ONUCVlan:
833 flow.SetMatchVlan(vs.SVlan)
834 case OLTSVlan:
835 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
836 flow.SetMatchVlan(vs.UniVlan)
837 flow.SetSetVlan(vs.SVlan)
838 } else if vs.UniVlan != of.VlanNone {
839 flow.SetMatchVlan(vs.UniVlan)
840 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
841 } else {
842 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
843 }
844 default:
845 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
846 return errorCodes.ErrInvalidParamInRequest
847 }
848 return nil
849}
850
851// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
852// based on different Vlan Controls
853func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
854 switch vs.VlanControl {
855 case None:
856 flow.SetMatchVlan(vs.SVlan)
857 case ONUCVlanOLTSVlan:
858 flow.SetMatchVlan(vs.SVlan)
859 flow.SetPopVlan()
860 case OLTCVlanOLTSVlan:
861 flow.SetMatchVlan(vs.SVlan)
862 flow.SetPopVlan()
863 flow.SetSetVlan(vs.UniVlan)
864 case ONUCVlan:
865 flow.SetMatchVlan(vs.SVlan)
866 case OLTSVlan:
867 flow.SetMatchVlan(vs.SVlan)
868 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
869 flow.SetSetVlan(vs.UniVlan)
870 } else {
871 flow.SetPopVlan()
872 }
873 default:
874 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
875 return errorCodes.ErrInvalidParamInRequest
876 }
877 return nil
878}
879
880// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
881// based on different Vlan Controls
882func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
883 switch vs.VlanControl {
884 case None:
885 flow.SetMatchVlan(vs.SVlan)
886 case ONUCVlanOLTSVlan:
887 if vs.UniVlan != of.VlanNone {
888 flow.SetMatchVlan(vs.UniVlan)
889 flow.SetSetVlan(vs.CVlan)
890 } else {
891 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
892 }
893 case OLTCVlanOLTSVlan:
894 flow.SetMatchVlan(vs.UniVlan)
895 case ONUCVlan:
896 if vs.UniVlan != of.VlanNone {
897 flow.SetMatchVlan(vs.UniVlan)
898 flow.SetSetVlan(vs.SVlan)
899 } else {
900 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
901 }
902 case OLTSVlan:
903 flow.SetMatchVlan(vs.UniVlan)
904 default:
905 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
906 return errorCodes.ErrInvalidParamInRequest
907 }
908 return nil
909}
910
911// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
912// based on different Vlan Controls
913func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
914 switch vs.VlanControl {
915 case None:
916 flow.SetMatchVlan(vs.SVlan)
917 case ONUCVlanOLTSVlan:
918 flow.SetMatchVlan(vs.CVlan)
919 if vs.UniVlan != of.VlanNone {
920 flow.SetSetVlan(vs.UniVlan)
921 } else {
922 flow.SetPopVlan()
923 }
924 case OLTCVlanOLTSVlan:
925 flow.SetMatchVlan(vs.UniVlan)
926 case ONUCVlan:
927 flow.SetMatchVlan(vs.SVlan)
928 if vs.UniVlan != of.VlanNone {
929 flow.SetSetVlan(vs.UniVlan)
930 } else {
931 flow.SetPopVlan()
932 }
933 case OLTSVlan:
934 flow.SetMatchVlan(vs.UniVlan)
935 default:
936 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
937 return errorCodes.ErrInvalidParamInRequest
938 }
939 return nil
940}
941
942// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530943func (vs *VoltService) SvcUpInd(cntx context.Context) {
944 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530945}
946
947// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530948func (vs *VoltService) SvcDownInd(cntx context.Context) {
949 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530950}
951
952// SetIpv4Addr to set ipv4 address
953func (vs *VoltService) SetIpv4Addr(addr net.IP) {
954 vs.Ipv4Addr = addr
955}
956
957// SetIpv6Addr to set ipv6 address
958func (vs *VoltService) SetIpv6Addr(addr net.IP) {
959 vs.Ipv6Addr = addr
960}
961
962// SetMacAddr to set mac address
963func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
964 vs.MacAddr = addr
965}
966
967// ----------------------------------------------
968// VOLT Application - Related to services
969// ---------------------------------------------
970// ---------------------------------------------------------------
971// Service CRUD functions. These are exposed to the overall binary
972// to be invoked from the point where the CRUD operations are received
973// from the external entities
974
975// AddService : A service in the context of VOLT is a subscriber or service of a
976// subscriber which is uniquely identified by a combination of MAC
977// address, VLAN tags, 802.1p bits. However, in the context of the
978// current implementation, a service is an entity that is identified by a
979// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
980// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530981func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530982 var mmUs, mmDs *VoltMeter
983 var err error
984
vinokuma926cb3e2023-03-29 11:41:06 +0530985 // Take the Device lock only in case of NB add request.
Naveen Sampath04696f72022-06-13 15:19:14 +0530986 // Allow internal adds since internal add happen only under
987 // 1. Restore Service from DB
988 // 2. Service Migration
989 if oper == nil {
990 if svc := va.GetService(cfg.Name); svc != nil {
991 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
992 return errors.New("Service Already Exists")
993 }
994 }
995
996 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
997 // Service doesn't exist. So create it and add to the port
998 vs := NewVoltService(&cfg)
999 if oper != nil {
1000 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1001 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1002 vs.Ipv4Addr = oper.Ipv4Addr
1003 vs.Ipv6Addr = oper.Ipv6Addr
1004 vs.MacLearning = cfg.MacLearning
1005 vs.PendingFlows = oper.PendingFlows
1006 vs.AssociatedFlows = oper.AssociatedFlows
1007 vs.DeleteInProgress = oper.DeleteInProgress
1008 vs.BwAvailInfo = oper.BwAvailInfo
1009 vs.Device = oper.Device
1010 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301011 // Sorting Pbit from highest
Naveen Sampath04696f72022-06-13 15:19:14 +05301012 sort.Slice(vs.Pbits, func(i, j int) bool {
1013 return vs.Pbits[i] > vs.Pbits[j]
1014 })
1015 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1016 }
1017 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1018
1019 // The bandwidth and shaper profile combined into meter
1020 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1021 vs.DsMeterID = mmDs.ID
1022 } else {
1023 return errors.New("DownStream meter profile not found")
1024 }
1025
1026 // The aggregated downstream meter profile
1027 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1028 // vs.AggDsMeterID = mmAg.ID
1029 // } else {
1030 // return errors.New("Aggregated meter profile not found")
1031 // }
1032
1033 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1034 // vs.UsMeterID = mmAg.ID
1035 // } else {
1036 // The bandwidth and shaper profile combined into meter
1037 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1038 vs.UsMeterID = mmUs.ID
1039 } else {
1040 return errors.New("Upstream meter profile not found")
1041 }
1042 //}
1043
1044 AppMutex.ServiceDataMutex.Lock()
1045 defer AppMutex.ServiceDataMutex.Unlock()
1046
1047 // Add the service to the VNET
1048 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1049 if vnet != nil {
1050 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1051 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301052 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301053 vpv.VpvLock.Unlock()
1054 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301055 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301056 }
1057 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301058 logger.Errorw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301059 return errors.New("VNET doesn't exist")
1060 }
1061
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301062 // If the device is already discovered, update the device name in service
1063 d, err := va.GetDeviceFromPort(vs.Port)
1064 if err == nil {
1065 vs.Device = d.Name
1066 }
1067
Naveen Sampath04696f72022-06-13 15:19:14 +05301068 vs.Version = database.PresentVersionMap[database.ServicePath]
1069 // Add the service to the volt application
1070 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301071 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301072
1073 if nil == oper {
Naveen Sampath04696f72022-06-13 15:19:14 +05301074 if !vs.UsHSIAFlowsApplied {
1075 vs.triggerServiceInProgressInd()
1076 }
1077
vinokuma926cb3e2023-03-29 11:41:06 +05301078 // Update meter profiles service count if service is being added from northbound
Naveen Sampath04696f72022-06-13 15:19:14 +05301079 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301080 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301081 if mmUs != nil {
1082 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301083 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301084 }
1085 //mmAg.AssociatedServices++
1086 //va.UpdateMeterProf(*mmAg)
vinokuma926cb3e2023-03-29 11:41:06 +05301087 logger.Debugw(ctx, "northbound-service-add-successful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301088 }
1089
1090 logger.Warnw(ctx, "Added Service to DB", log.Fields{"Name": vs.Name, "Port": (vs.Port), "ML": vs.MacLearning})
1091 return nil
1092}
1093
vinokuma926cb3e2023-03-29 11:41:06 +05301094// DelServiceWithPrefix - Deletes service with the provided prefix.
Naveen Sampath04696f72022-06-13 15:19:14 +05301095// Added for DT/TT usecase with sadis replica interface
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301096func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301097 va.ServiceByName.Range(func(key, value interface{}) bool {
1098 srvName := key.(string)
1099 vs := value.(*VoltService)
1100 if strings.Contains(srvName, prefix) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301101 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301102
1103 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1104 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1105 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1106
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301107 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301108 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1109 }
1110 }
1111 return true
1112 })
1113}
1114
1115// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301116func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301117 AppMutex.ServiceDataMutex.Lock()
1118 defer AppMutex.ServiceDataMutex.Unlock()
1119
1120 logger.Warnw(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
1121 var noFlowsPresent bool
1122
1123 vsIntf, ok := va.ServiceByName.Load(name)
1124 if !ok {
1125 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1126 return
1127 }
1128 vs := vsIntf.(*VoltService)
1129 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1130 if vpv == nil {
1131 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
1132 return
1133 }
1134
vinokuma926cb3e2023-03-29 11:41:06 +05301135 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301136 vs.DeleteInProgress = true
1137 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301138 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301139
1140 if len(vs.AssociatedFlows) == 0 {
1141 noFlowsPresent = true
1142 }
1143 vpv.VpvLock.Lock()
1144 defer vpv.VpvLock.Unlock()
1145
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301146 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301147
1148 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301149 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301150 }
1151 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 +05301152 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301153 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301154 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301155 }
1156
1157 // Delete the service immediately in case of Force Delete
1158 // This will be enabled when profile reconciliation happens after restore
1159 // of backedup data
1160 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301161 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301162 GetApplication().ServiceByName.Delete(vs.Name)
1163 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1164 }
1165
Naveen Sampath04696f72022-06-13 15:19:14 +05301166 if nil != newSvc {
1167 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1168 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1169 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301170
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301171 logger.Infow(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
1172
1173 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1174 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301175 if aggMeter.AssociatedServices > 0 {
1176 aggMeter.AssociatedServices--
1177 logger.Infow(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
1178 va.UpdateMeterProf(cntx, *aggMeter)
1179 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301180 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301181 }
1182 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301183 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1184 if dsMeter.AssociatedServices > 0 {
1185 dsMeter.AssociatedServices--
1186 logger.Infow(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
1187 va.UpdateMeterProf(cntx, *dsMeter)
1188 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301189 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301190 }
1191 if vs.AggDsMeterID != vs.UsMeterID {
1192 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301193 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1194 if usMeter.AssociatedServices > 0 {
1195 usMeter.AssociatedServices--
1196 logger.Infow(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
1197 va.UpdateMeterProf(cntx, *usMeter)
1198 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301199 }
1200 }
1201 }
1202
1203 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301204 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301205 }
1206
vinokuma926cb3e2023-03-29 11:41:06 +05301207 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301208 va.ServiceCounters.Delete(name)
1209 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301210 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301211 }
1212}
1213
vinokuma926cb3e2023-03-29 11:41:06 +05301214// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301215// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301216func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301217 // Using locks instead of concurrent map for PendingFlows to avoid
1218 // race condition during flow response indication processing
1219 vs.ServiceLock.Lock()
1220 defer vs.ServiceLock.Unlock()
1221
1222 for cookie := range flow.SubFlows {
1223 cookie := strconv.FormatUint(cookie, 10)
1224 fe := &FlowEvent{
1225 eType: EventTypeServiceFlowAdded,
1226 device: device.Name,
1227 cookie: cookie,
1228 eventData: vs,
1229 }
1230 device.RegisterFlowAddEvent(cookie, fe)
1231 vs.PendingFlows[cookie] = true
1232 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301233 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301234}
1235
vinokuma926cb3e2023-03-29 11:41:06 +05301236// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301237// If no more pending flows, HSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301238func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301239 if vs.DeleteInProgress {
1240 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1241 return
1242 }
1243 vs.ServiceLock.Lock()
1244
1245 if _, ok := vs.PendingFlows[cookie]; !ok {
1246 logger.Errorw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1247 vs.ServiceLock.Unlock()
1248 return
1249 }
1250
1251 delete(vs.PendingFlows, cookie)
1252 vs.AssociatedFlows[cookie] = true
1253 vs.ServiceLock.Unlock()
1254 var prevBwAvail, presentBwAvail string
1255 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1256 prevBwAvail = bwAvailInfo.PrevBw
1257 presentBwAvail = bwAvailInfo.PresentBw
1258 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301259 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301260 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301261 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301262
1263 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301264 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1265 if err != nil {
1266 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1267 return
1268 } else if device.State != controller.DeviceStateUP {
1269 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1270 return
1271 }
1272
1273 if vs.Trigger == ServiceVlanUpdate {
1274 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301275 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301276 }
1277 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1278 return
1279 }
1280 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1281}
1282
vinokuma926cb3e2023-03-29 11:41:06 +05301283// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301284// Trigger service failure indication to NB
1285func (vs *VoltService) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
1286 vs.ServiceLock.RLock()
1287
1288 if _, ok := vs.PendingFlows[cookie]; !ok {
1289 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1290 vs.ServiceLock.RUnlock()
1291 return
1292 }
1293 vs.ServiceLock.RUnlock()
1294 logger.Errorw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1295 vs.triggerServiceFailureInd(errorCode, errReason)
1296}
1297
vinokuma926cb3e2023-03-29 11:41:06 +05301298// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301299// Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301300func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301301 if !vs.ForceDelete {
1302 // Using locks instead of concurrent map for AssociatedFlows to avoid
1303 // race condition during flow response indication processing
1304 vs.ServiceLock.Lock()
1305 defer vs.ServiceLock.Unlock()
1306
1307 for cookie := range flow.SubFlows {
1308 cookie := strconv.FormatUint(cookie, 10)
1309 fe := &FlowEvent{
1310 eType: EventTypeServiceFlowRemoved,
1311 cookie: cookie,
1312 eventData: vs,
1313 }
1314 device.RegisterFlowDelEvent(cookie, fe)
1315 }
1316 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301317 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301318}
1319
vinokuma926cb3e2023-03-29 11:41:06 +05301320// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301321func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301322 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301323 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301324 GetApplication().ServiceByName.Delete(vs.Name)
1325 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1326 }
1327}
1328
vinokuma926cb3e2023-03-29 11:41:06 +05301329// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301330// If no more associated flows, DelHSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301331func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301332 // if vs.DeleteInProgress {
1333 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1334 // return
1335 // }
1336 vs.ServiceLock.Lock()
1337 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1338
1339 if _, ok := vs.AssociatedFlows[cookie]; ok {
1340 delete(vs.AssociatedFlows, cookie)
1341 } else if _, ok := vs.PendingFlows[cookie]; ok {
1342 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})
1343 } else {
1344 logger.Errorw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
1345 }
1346
1347 vs.ServiceLock.Unlock()
1348
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301349 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301350
1351 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301352 device := GetApplication().GetDevice(vs.Device)
1353 if device == nil {
1354 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1355 return
1356 } else if device.State != controller.DeviceStateUP {
1357 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1358 return
1359 }
1360
1361 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301362 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301363 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301364 return
1365 }
1366 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 +05301367 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301368
1369 return
1370 }
1371 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1372}
1373
vinokuma926cb3e2023-03-29 11:41:06 +05301374// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301375// Trigger service failure indication to NB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301376func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301377 vs.ServiceLock.RLock()
1378
1379 if _, ok := vs.AssociatedFlows[cookie]; !ok {
1380 logger.Errorw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1381 vs.ServiceLock.RUnlock()
1382 return
1383 }
1384 if vs.DeleteInProgress {
1385 delete(vs.AssociatedFlows, cookie)
1386 }
1387 vs.ServiceLock.RUnlock()
1388 logger.Errorw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1389
1390 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301391 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301392}
1393
1394func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
1395 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1396 if err != nil {
1397 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1398 return
1399 } else if device.State != controller.DeviceStateUP {
1400 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1401 return
1402 }
1403}
1404
1405// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301406func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301407 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301408 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301409 for _, vs := range vss {
1410 b, ok := vs.Value.([]byte)
1411 if !ok {
1412 logger.Warn(ctx, "The value type is not []byte")
1413 continue
1414 }
1415 var vvs VoltService
1416 err := json.Unmarshal(b, &vvs)
1417 if err != nil {
1418 logger.Warn(ctx, "Unmarshal of VNET failed")
1419 continue
1420 }
1421 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301422 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301423 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1424 }
1425
1426 if vvs.VoltServiceOper.DeleteInProgress {
1427 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1428 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1429 }
1430 }
1431}
1432
1433// GetService to get service
1434func (va *VoltApplication) GetService(name string) *VoltService {
1435 if vs, ok := va.ServiceByName.Load(name); ok {
1436 return vs.(*VoltService)
1437 }
1438 return nil
1439}
1440
1441// GetCircuitID to get circuit id
1442func (vs *VoltService) GetCircuitID() []byte {
1443 return []byte(vs.CircuitID)
1444}
1445
1446// GetRemoteID to get remote id
1447func (vs *VoltService) GetRemoteID() []byte {
1448 return []byte(vs.RemoteID)
1449}
1450
1451// IPAssigned to check if ip is assigned
1452func (vs *VoltService) IPAssigned() bool {
1453 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1454 return true
1455 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1456 return true
1457 }
1458 return false
1459}
1460
1461// GetServiceNameFromCookie to get service name from cookie
1462func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
Naveen Sampath04696f72022-06-13 15:19:14 +05301463 var vlan uint64
1464 vlanControl := (tableMetadata >> 32) & 0xF
1465
1466 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1467 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1468 vlan = (tableMetadata >> 16) & 0xFFFF
1469 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301470 // Fetching CVlan for other vlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301471 vlan = cookie >> 52
1472 }
1473 logger.Infow(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
1474 var vlans []of.VlanType
1475 vlans = append(vlans, of.VlanType(vlan))
1476 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1477 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301478 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301479 } else {
1480 logger.Errorw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
1481 }
1482 return service
1483}
1484
vinokuma926cb3e2023-03-29 11:41:06 +05301485// MigrateServicesReqStatus - update vnet request status
Naveen Sampath04696f72022-06-13 15:19:14 +05301486type MigrateServicesReqStatus string
1487
1488const (
vinokuma926cb3e2023-03-29 11:41:06 +05301489 // MigrateSrvsReqInit constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301490 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
vinokuma926cb3e2023-03-29 11:41:06 +05301491 // MigrateSrvsReqDeactTriggered constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301492 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
vinokuma926cb3e2023-03-29 11:41:06 +05301493 // MigrateSrvsReqCompleted constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301494 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1495)
1496
vinokuma926cb3e2023-03-29 11:41:06 +05301497// MigrateServicesRequest - update vnet request params
Naveen Sampath04696f72022-06-13 15:19:14 +05301498type MigrateServicesRequest struct {
1499 ID string
1500 OldVnetID string
1501 NewVnetID string
1502 ServicesList map[string]bool
1503 DeviceID string
1504 Status MigrateServicesReqStatus
1505 MigrateServicesLock sync.RWMutex
1506}
1507
1508func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
Naveen Sampath04696f72022-06-13 15:19:14 +05301509 var msr MigrateServicesRequest
1510 msr.OldVnetID = oldVnetID
1511 msr.NewVnetID = newVnetID
1512 msr.ID = id
1513 msr.ServicesList = serviceMap
1514 msr.DeviceID = deviceID
1515 msr.Status = MigrateSrvsReqInit
1516 return &msr
1517}
1518
vinokuma926cb3e2023-03-29 11:41:06 +05301519// GetMsrKey - generates migrate service request key
Naveen Sampath04696f72022-06-13 15:19:14 +05301520func (msr *MigrateServicesRequest) GetMsrKey() string {
1521 return msr.OldVnetID + "-" + msr.ID
1522}
1523
1524// //isRequestComplete - return if all request has been processed and completed
1525// // RequestProcessed indicates that all the profile de-activation has been triggered
1526// // And the associated profiles indicates the profiles awaiting results
1527// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1528// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1529// return (len(edr.AssociatedProfiles) == 0)
1530// }
1531
vinokuma926cb3e2023-03-29 11:41:06 +05301532// WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301533func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301534 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)})
1535 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301536 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301537 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301538 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301539 }
1540 }
1541}
1542
vinokuma926cb3e2023-03-29 11:41:06 +05301543// MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301544func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301545 logger.Warnw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
1546 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
1547 return errors.New("Old Vnet Id not found")
1548 }
1549 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
1550 return errors.New("New Vnet Id not found")
1551 }
1552
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301553 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301554 if d == nil {
1555 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1556 return errorCodes.ErrDeviceNotFound
1557 }
1558
1559 serviceMap := make(map[string]bool)
1560
1561 for _, service := range serviceList {
1562 serviceMap[service] = false
1563 }
1564 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301565 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301566
1567 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301568 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301569 return nil
1570}
1571
vinokuma926cb3e2023-03-29 11:41:06 +05301572// ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301573func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301574 va := GetApplication()
1575 for srv, processed := range msr.ServicesList {
vinokuma926cb3e2023-03-29 11:41:06 +05301576 // Indicates new service is already created and only deletion of old one is pending
Naveen Sampath04696f72022-06-13 15:19:14 +05301577 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301578 va.DelService(cntx, srv, true, nil, true)
1579 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301580 continue
1581 }
1582
1583 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1584 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1585 vs := vsIntf.(*VoltService)
1586 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1587 if vpv == nil {
1588 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
1589 continue
1590 }
1591 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1592 vpv.Blocked = true
1593
1594 // setDeactTrigger := func(key, value interface{}) bool {
1595 // vs := value.(*VoltService)
1596 vs.ServiceLock.Lock()
1597 vs.UpdateInProgress = true
1598 metadata := &MigrateServiceMetadata{
1599 NewVnetID: msr.NewVnetID,
1600 RequestID: msr.ID,
1601 }
1602 vs.Metadata = metadata
1603 vs.ServiceLock.Unlock()
1604
vinokuma926cb3e2023-03-29 11:41:06 +05301605 // vpv flows will be removed when last service is removed from it and
Naveen Sampath04696f72022-06-13 15:19:14 +05301606 // new vpv flows will be installed when new service is added
1607 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301608 vpv.DelTrapFlows(cntx)
1609 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301610 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301611 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301612 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301613 }
1614 } else {
1615 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1616 }
1617 }
1618}
1619
vinokuma926cb3e2023-03-29 11:41:06 +05301620// AddMigratingServices - store msr info to device obj
Naveen Sampath04696f72022-06-13 15:19:14 +05301621func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301622 var msrMap *util.ConcurrentMap
1623 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1624 msrMap = util.NewConcurrentMap()
1625 } else {
1626 msrMap = msrMapIntf.(*util.ConcurrentMap)
1627 }
1628
1629 msrMap.Set(msr.ID, msr)
1630 logger.Infow(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
1631
1632 d.MigratingServices.Set(msr.OldVnetID, msrMap)
1633 logger.Infow(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301634}
1635
vinokuma926cb3e2023-03-29 11:41:06 +05301636// getMigrateServicesRequest - fetches msr info from device
Naveen Sampath04696f72022-06-13 15:19:14 +05301637func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
1638 if vd := va.GetDevice(deviceID); vd != nil {
1639 logger.Infow(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
1640 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1641 msrList := msrListIntf.(*util.ConcurrentMap)
1642 logger.Infow(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
1643 if msrObj, ok := msrList.Get(requestID); ok {
1644 return msrObj.(*MigrateServicesRequest)
1645 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301646 }
1647 }
1648 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
1649 return nil
1650}
1651
vinokuma926cb3e2023-03-29 11:41:06 +05301652// updateMigrateServicesRequest - Updates the device with updated msr
Naveen Sampath04696f72022-06-13 15:19:14 +05301653func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
1654 if vd := va.GetDevice(deviceID); vd != nil {
1655 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1656 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1657 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1658 }
1659 }
1660 }
1661}
1662
vinokuma926cb3e2023-03-29 11:41:06 +05301663// updateVnetProfile - Called on flow process completion
1664// Removes old service and creates new VPV & service with updated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301665func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301666 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 +05301667
1668 nvs := VoltService{}
1669 nvs.VoltServiceCfg = vs.VoltServiceCfg
1670 nvs.Device = vs.Device
1671 nvs.Ipv4Addr = vs.Ipv4Addr
1672 nvs.Ipv6Addr = vs.Ipv6Addr
1673 nvs.UsMeterID = vs.UsMeterID
1674 nvs.DsMeterID = vs.DsMeterID
1675 nvs.AggDsMeterID = vs.AggDsMeterID
1676 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1677 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1678 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1679 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1680 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1681 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1682 nvs.PendingFlows = vs.PendingFlows
1683 nvs.AssociatedFlows = vs.AssociatedFlows
1684 nvs.DeleteInProgress = vs.DeleteInProgress
1685 nvs.ForceDelete = vs.ForceDelete
1686 nvs.BwAvailInfo = vs.BwAvailInfo
1687 nvs.UpdateInProgress = vs.UpdateInProgress
1688
1689 if nvs.DeleteInProgress {
1690 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1691 return
1692 }
1693
1694 metadata := vs.Metadata.(*MigrateServiceMetadata)
1695 oldVnetID := vs.VnetID
Naveen Sampath04696f72022-06-13 15:19:14 +05301696 oldSrvName := vs.Name
1697
1698 if metadata == nil || metadata.NewVnetID == "" {
1699 logger.Errorw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
1700 return
1701 }
1702
vinokuma926cb3e2023-03-29 11:41:06 +05301703 nvs.VnetID = metadata.NewVnetID
1704 id := metadata.RequestID
1705
1706 // First add the new service and then only delete the old service
Naveen Sampath04696f72022-06-13 15:19:14 +05301707 // Since if post del service in case of pod crash or reboot, the service data will be lost
1708 va := GetApplication()
1709 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1710 vnets := strings.Split(metadata.NewVnetID, "-")
1711 svlan, _ := strconv.Atoi(vnets[0])
1712 nvs.SVlan = of.VlanType(svlan)
1713 nvs.UpdateInProgress = false
1714 nvs.Metadata = nil
1715 nvs.Trigger = ServiceVlanUpdate
1716
1717 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1718 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1719 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1720
vinokuma926cb3e2023-03-29 11:41:06 +05301721 // TODO:Nav Pass a copy, not the pointer
Naveen Sampath04696f72022-06-13 15:19:14 +05301722 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 +05301723 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301724 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1725 }
1726 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1727
1728 msr.ServicesList[oldSrvName] = true
1729 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301730 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301731
1732 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 +05301733 va.DelService(cntx, oldSrvName, true, nil, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301734 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 +05301735 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301736}
1737
vinokuma926cb3e2023-03-29 11:41:06 +05301738// serviceMigrated - called on successful service updation
Naveen Sampath04696f72022-06-13 15:19:14 +05301739// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301740func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301741 msr.MigrateServicesLock.Lock()
1742 defer msr.MigrateServicesLock.Unlock()
1743
1744 delete(msr.ServicesList, serviceName)
1745
1746 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301747 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301748 return
1749 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301750 msr.WriteToDB(cntx)
vinokuma926cb3e2023-03-29 11:41:06 +05301751 // TODO:Nav - Need for any Response to SubMgr?
Naveen Sampath04696f72022-06-13 15:19:14 +05301752}
1753
vinokuma926cb3e2023-03-29 11:41:06 +05301754// TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301755func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1756 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301757}
1758
vinokuma926cb3e2023-03-29 11:41:06 +05301759// FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301760func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301761 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301762 for _, msr := range msrList {
1763 b, ok := msr.Value.([]byte)
1764 if !ok {
1765 logger.Warn(ctx, "The value type is not []byte")
1766 continue
1767 }
1768 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301769 msrAction(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301770 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 +05301771 }
1772}
1773
1774// createMigrateServicesFromString to create Service from string
1775func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
1776 var msr MigrateServicesRequest
1777 if err := json.Unmarshal(b, &msr); err == nil {
1778 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301779 } else {
1780 logger.Warn(ctx, "Unmarshal failed")
1781 }
1782 return &msr
1783}
1784
vinokuma926cb3e2023-03-29 11:41:06 +05301785// storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301786func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301787 d := GetApplication().GetDevice(msr.DeviceID)
1788 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301789 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301790}
1791
vinokuma926cb3e2023-03-29 11:41:06 +05301792// forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301793func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301794 for srv := range msr.ServicesList {
1795 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301796 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301797 }
1798 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301799 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301800}
1801
vinokuma926cb3e2023-03-29 11:41:06 +05301802// nolint: gocyclo
1803// DeepEqualServicecfg - checks if the given service cfgs are same
Naveen Sampath04696f72022-06-13 15:19:14 +05301804func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1805 if nvs.Name != evs.Name {
1806 return false
1807 }
1808 if nvs.UniVlan != evs.UniVlan {
1809 return false
1810 }
1811 if nvs.CVlan != evs.CVlan {
1812 return false
1813 }
1814 if nvs.SVlan != evs.SVlan {
1815 return false
1816 }
1817 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1818 return false
1819 }
1820 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1821 return false
1822 }
1823 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1824 return false
1825 }
1826 if nvs.TechProfileID != evs.TechProfileID {
1827 return false
1828 }
1829 if nvs.CircuitID != evs.CircuitID {
1830 return false
1831 }
1832 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1833 return false
1834 }
1835 if nvs.Port != evs.Port {
1836 return false
1837 }
1838 if nvs.PonPort != evs.PonPort {
1839 return false
1840 }
1841 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1842 return false
1843 }
1844 if nvs.IsOption82Disabled != evs.IsOption82Disabled {
1845 return false
1846 }
1847 if nvs.IgmpEnabled != evs.IgmpEnabled {
1848 return false
1849 }
1850 if nvs.McastService != evs.McastService {
1851 return false
1852 }
1853 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1854 return false
1855 }
1856 if nvs.UsMeterProfile != evs.UsMeterProfile {
1857 return false
1858 }
1859 if nvs.DsMeterProfile != evs.DsMeterProfile {
1860 return false
1861 }
1862 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
1863 return false
1864 }
1865 if nvs.VnetID != evs.VnetID {
1866 return false
1867 }
1868 if nvs.MvlanProfileName != evs.MvlanProfileName {
1869 return false
1870 }
1871 if nvs.RemoteIDType != evs.RemoteIDType {
1872 return false
1873 }
1874 if nvs.SchedID != evs.SchedID {
1875 return false
1876 }
1877 if nvs.AllowTransparent != evs.AllowTransparent {
1878 return false
1879 }
1880 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
1881 return false
1882 }
1883 if nvs.DataRateAttr != evs.DataRateAttr {
1884 return false
1885 }
1886 if nvs.MinDataRateUs != evs.MinDataRateUs {
1887 return false
1888 }
1889 if nvs.MinDataRateDs != evs.MinDataRateDs {
1890 return false
1891 }
1892 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
1893 return false
1894 }
1895 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
1896 return false
1897 }
1898
1899 return true
1900}
1901
vinokuma926cb3e2023-03-29 11:41:06 +05301902// TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301903func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
vinokuma926cb3e2023-03-29 11:41:06 +05301904 // Clear the Flows flag if already set
1905 // This case happens only in case of some race condition
Naveen Sampath04696f72022-06-13 15:19:14 +05301906 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301907 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301908 logger.Errorw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1909 }
1910 }
1911
1912 if vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301913 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301914 logger.Errorw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1915 }
1916 }
1917
1918 vs.ServiceLock.Lock()
1919 cookieList := []uint64{}
1920 for cookie := range vs.AssociatedFlows {
1921 cookieList = append(cookieList, convertToUInt64(cookie))
1922 }
1923 vs.ServiceLock.Unlock()
1924
1925 if len(cookieList) == 0 {
1926 return false
1927 }
1928
vinokuma926cb3e2023-03-29 11:41:06 +05301929 // Trigger Flow Delete
Naveen Sampath04696f72022-06-13 15:19:14 +05301930 for _, cookie := range cookieList {
1931 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
1932 flow := &of.VoltFlow{}
1933 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1934 subFlow := of.NewVoltSubFlow()
1935 subFlow.Cookie = cookie
1936 flow.SubFlows[cookie] = subFlow
1937 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301938 if err := vs.DelFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301939 logger.Errorw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
1940 }
1941 }
1942 }
1943 return true
1944}
1945
vinokuma926cb3e2023-03-29 11:41:06 +05301946// triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
Naveen Sampath04696f72022-06-13 15:19:14 +05301947func (vs *VoltService) triggerServiceInProgressInd() {
1948}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301949
vinokuma926cb3e2023-03-29 11:41:06 +05301950// JSONMarshal wrapper function for json Marshal VoltService
1951func (vs *VoltService) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301952 return json.Marshal(VoltService{
1953 VoltServiceCfg: vs.VoltServiceCfg,
1954 VoltServiceOper: VoltServiceOper{
1955 Device: vs.VoltServiceOper.Device,
1956 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
1957 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
1958 UsMeterID: vs.VoltServiceOper.UsMeterID,
1959 DsMeterID: vs.VoltServiceOper.DsMeterID,
1960 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
1961 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
1962 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
1963 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
1964 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
1965 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
1966 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
1967 PendingFlows: vs.VoltServiceOper.PendingFlows,
1968 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
1969 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
1970 ForceDelete: vs.VoltServiceOper.ForceDelete,
1971 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
1972 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
1973 Metadata: vs.VoltServiceOper.Metadata,
1974 },
1975 })
1976}
Tinoj Josephec742f62022-09-29 19:11:10 +05301977
1978// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301979func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05301980 var svcList []*VoltService
1981 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
1982 va.ServiceByName.Range(func(key, value interface{}) bool {
1983 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301984 if len(deviceID) > 0 {
1985 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05301986 if deviceID == vs.Device && portNo == vs.Port {
1987 svcList = append(svcList, vs)
1988 }
1989 } else {
1990 if deviceID == vs.Device {
1991 svcList = append(svcList, vs)
1992 }
1993 }
1994 } else {
1995 svcList = append(svcList, vs)
1996 }
1997 return true
1998 })
1999 return svcList, nil
2000}
2001
2002// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302003func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302004 logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302005 device, err := va.GetDeviceFromPort(portNo)
2006 if err != nil {
2007 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2008 return errorCodes.ErrPortNotFound
2009 }
2010 // If device id is not provided check only port number
2011 if deviceID == DeviceAny {
2012 deviceID = device.Name
2013 } else if deviceID != device.Name {
2014 logger.Errorw(ctx, "Wrong Device ID", log.Fields{"Device": deviceID, "Port": portNo})
2015 return errorCodes.ErrDeviceNotFound
2016 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302017 va.ServiceByName.Range(func(key, value interface{}) bool {
2018 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302019 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302020 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302021 logger.Infow(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302022 return true
2023 }
2024 if portNo == vs.Port && !vs.IsActivated {
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302025 p := device.GetPort(vs.Port)
Tinoj Josephec742f62022-09-29 19:11:10 +05302026 if p == nil {
2027 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2028 return true
2029 }
2030 logger.Infow(ctx, "Service Activate", log.Fields{"Name": vs.Name})
2031 vs.IsActivated = true
2032 va.ServiceByName.Store(vs.Name, vs)
2033 vs.WriteToDb(cntx)
2034 // If port is already up send indication to vpv
2035 if p.State == PortStateUp {
2036 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2037 // PortUp call initiates flow addition
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302038 vpv.PortUpInd(cntx, device, portNo)
Tinoj Josephec742f62022-09-29 19:11:10 +05302039 } else {
2040 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2041 }
2042 }
2043 }
2044 return true
2045 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302046 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302047}
2048
2049// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302050func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302051 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2052 va.ServiceByName.Range(func(key, value interface{}) bool {
2053 vs := value.(*VoltService)
2054 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302055 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2056 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
vinokuma926cb3e2023-03-29 11:41:06 +05302057 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 +05302058 return true
2059 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302060 if portNo == vs.Port && vs.IsActivated {
Tinoj Josephec742f62022-09-29 19:11:10 +05302061 vs.IsActivated = false
2062 va.ServiceByName.Store(vs.Name, vs)
2063 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302064 device, err := va.GetDeviceFromPort(portNo)
2065 if err != nil {
2066 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2067 // So no error is returned
2068 logger.Infow(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2069 return true
2070 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302071 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302072 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302073 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2074 // Port down call internally deletes all the flows
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302075 vpv.PortDownInd(cntx, deviceID, portNo, true)
Tinoj Josephec742f62022-09-29 19:11:10 +05302076 if vpv.IgmpEnabled {
2077 va.ReceiverDownInd(cntx, deviceID, portNo)
2078 }
2079 } else {
2080 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2081 }
2082 }
2083 }
2084 return true
2085 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302086 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302087}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302088
vinokuma926cb3e2023-03-29 11:41:06 +05302089// GetServicePbit to get first set bit in the pbit map
2090// returns -1 : If configured to match on all pbits
2091// returns 8 : If no pbits are configured
2092// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302093func (vs *VoltService) GetServicePbit() int {
2094 if vs.IsPbitExist(of.PbitMatchAll) {
2095 return -1
2096 }
vinokuma926cb3e2023-03-29 11:41:06 +05302097 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302098 if vs.IsPbitExist(of.PbitType(pbit)) {
2099 return pbit
2100 }
2101 }
2102 return int(of.PbitMatchNone)
2103}