blob: 690f348608e57b91cb9af989d837c8718365ba14 [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.
14*/
15
16package application
17
18import (
19 "bytes"
20 "encoding/json"
21 "errors"
Tinoj Joseph07cc5372022-07-18 22:53:51 +053022 "context"
Naveen Sampath04696f72022-06-13 15:19:14 +053023 "net"
24 "reflect"
25 infraerrorCodes "voltha-go-controller/internal/pkg/errorcodes"
26 "sort"
27 "strconv"
28 "strings"
29 "sync"
30
31 "github.com/google/gopacket/layers"
32
33 "voltha-go-controller/internal/pkg/controller"
34 cntlr "voltha-go-controller/internal/pkg/controller"
35 "voltha-go-controller/database"
36 "voltha-go-controller/internal/pkg/of"
37 "voltha-go-controller/internal/pkg/util"
38 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
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"
45)
46
47// VoltServiceCfg structure
48// Name - Uniquely identifies a service across the entire application
49// UniVlan - The VLAN of the packets entering the UNI of ONU
50// CVlan - The VLAN to transalate to/from on the PON link
51// SVlan - The outer VLAN to be used on the NNI of OLT.
52// - In general, 4096 is used as NO VLAN for all the above
53// SVlanTpid - SVlan Tag Protocl Identifier
54// Pbits - Each bit of uint8 represents one p-bit. MSB is pbit 7
55// DhcpRelay - Whether it is turned on/off
56// CircuitId - The circuit id to be used with DHCP relay. Unused otherwise
57// RemoveId - Same as above
58// Port - The access port for the service. Each service has a single access
59// port. The converse is not always true
60// MacLearning - If MAC learning is turned on, the MAC address learned from the
61// the service activation is used in programming flows
62// MacAddress - The MAC hardware address learnt on the UNI interface
63// MacAddresses - Not yet implemented. To be used to learn more MAC addresses
64type VoltServiceCfg struct {
65 Name string
66 UniVlan of.VlanType
67 CVlan of.VlanType
68 SVlan of.VlanType
69 SVlanTpid layers.EthernetType
70 MacAddr net.HardwareAddr
71 Pbits []of.PbitType
72 DsRemarkPbitsMap map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
73 TechProfileID uint16
74 CircuitID string
75 RemoteID []byte
76 Port string
77 PonPort uint32
78 MacLearning MacLearningType
79 IsOption82Disabled bool
80 IgmpEnabled bool
81 McastService bool
82 ONTEtherTypeClassification int
83 VlanControl VlanControl
84 UsMeterProfile string
85 DsMeterProfile string
86 AggDsMeterProfile string
87 VnetID string
88 MvlanProfileName string
89 RemoteIDType string
90 SchedID int
91 AllowTransparent bool
92 EnableMulticastKPI bool
93 DataRateAttr string
94 MinDataRateUs uint32
95 MinDataRateDs uint32
96 MaxDataRateUs uint32
97 MaxDataRateDs uint32
98
99 Trigger ServiceTrigger
100}
101
102// VoltServiceOper structure
103type VoltServiceOper struct {
104 //MacLearning bool
105 //MacAddr net.HardwareAddr
106 Device string
107 Ipv4Addr net.IP
108 Ipv6Addr net.IP
109
110 UsMeterID uint32
111 DsMeterID uint32
112 AggDsMeterID uint32
113
114 //Multiservice-Fix
115 UsHSIAFlowsApplied bool
116 DsHSIAFlowsApplied bool
117 UsDhcpFlowsApplied bool
118 DsDhcpFlowsApplied bool
119 IgmpFlowsApplied bool
120 Icmpv6FlowsApplied bool
121
122 ServiceLock sync.RWMutex `json:"-"`
123 PendingFlows map[string]bool
124 AssociatedFlows map[string]bool
125 DeleteInProgress bool
126 ForceDelete bool
127 BwAvailInfo string
128
129 UpdateInProgress bool
130 Metadata interface{}
131}
132
133// VoltService structure
134type VoltService struct {
135 VoltServiceCfg
136 VoltServiceOper
137 Version string
138}
139
140//ServiceTrigger - Service activation trigger
141type ServiceTrigger int
142
143const (
144 //NBActivate - Service added due to NB Action
145 NBActivate ServiceTrigger = 0
146 //ServiceVlanUpdate - Service added due to Svlan Update
147 ServiceVlanUpdate ServiceTrigger = 1
148)
149
150// AppMutexes structure
151type AppMutexes struct {
152 ServiceDataMutex sync.Mutex `json:"-"`
153 VnetMutex sync.Mutex `json:"-"`
154}
155
156//MigrateServiceMetadata - migrate services request metadata
157type MigrateServiceMetadata struct {
158 NewVnetID string
159 RequestID string
160}
161
162// AppMutex variable
163var AppMutex AppMutexes
164
165// NewVoltService for constructor for volt service
166func NewVoltService(cfg *VoltServiceCfg) *VoltService {
167 var vs VoltService
168 vs.VoltServiceCfg = *cfg
169 vs.UsHSIAFlowsApplied = false
170 vs.DsHSIAFlowsApplied = false
171 vs.DeleteInProgress = false
172 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
173
174 vs.MacAddr = cfg.MacAddr
175 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
176 vs.Ipv6Addr = net.ParseIP("::")
177 vs.PendingFlows = make(map[string]bool)
178 vs.AssociatedFlows = make(map[string]bool)
179 return &vs
180}
181
182// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530183func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530184
185 vs.ServiceLock.RLock()
186 defer vs.ServiceLock.RUnlock()
187
188 if vs.DeleteInProgress {
189 logger.Warnw(ctx, "Skipping Redis Update for Service, Service delete in progress", log.Fields{"Service": vs.Name})
190 return
191 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530192 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530193}
194
195//ForceWriteToDb force commit a service to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530196func (vs *VoltService) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530197 b, err := json.Marshal(vs)
198
199 if err != nil {
200 logger.Errorw(ctx, "Json Marshal Failed for Service", log.Fields{"Service": vs.Name})
201 return
202 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530203 if err1 := db.PutService(cntx, vs.Name, string(b)); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530204 logger.Errorw(ctx, "DB write oper failed for Service", log.Fields{"Service": vs.Name})
205 }
206}
207
208// isDataRateAttrPresent to check if data attribute is present
209func (vs *VoltService) isDataRateAttrPresent() bool {
210 return vs.DataRateAttr == DSLAttrEnabled
211}
212
213// DelFromDb delete a service from DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530214func (vs *VoltService) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530215 logger.Debugw(ctx, "Deleting Service from DB", log.Fields{"Name": vs.Name})
216 //TODO - Need to understand and delete the second call
217 //Calling twice has worked though don't know why
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530218 _ = db.DelService(cntx, vs.Name)
219 _ = db.DelService(cntx, vs.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530220}
221
222// MatchesVlans find the service that matches the VLANs. In this case it is
223// purely based on CVLAN. The CVLAN can sufficiently be used to
224// match a service
225func (vs *VoltService) MatchesVlans(vlans []of.VlanType) bool {
226 if len(vlans) != 1 {
227 return false
228 }
229
230 if vlans[0] == vs.CVlan {
231 return true
232 }
233 return false
234}
235
236// MatchesPbits allows matching a service to a pbit. This is used
237// to search for a service matching the pbits, typically to identify
238// attributes for other flows such as DHCP, IGMP, etc.
239func (vs *VoltService) MatchesPbits(pbits []of.PbitType) bool {
240 for _, pbit := range pbits {
241 for _, pb := range vs.Pbits {
242 if pb == pbit {
243 return true
244 }
245 }
246 }
247 return false
248}
249
250// IsPbitExist allows matching a service to a pbit. This is used
251// to search for a service matching the pbit
252func (vs *VoltService) IsPbitExist(pbit of.PbitType) bool {
253 for _, pb := range vs.Pbits {
254 if pb == pbit {
255 return true
256 }
257 }
258 return false
259}
260
261// AddHsiaFlows - Adds US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530262func (vs *VoltService) AddHsiaFlows(cntx context.Context) {
263 if err := vs.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530264 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
265 vs.triggerServiceFailureInd(statusCode, statusMessage)
266 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530267 if err := vs.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530268 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
269 vs.triggerServiceFailureInd(statusCode, statusMessage)
270 }
271}
272
273//DelHsiaFlows - Deletes US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530274func (vs *VoltService) DelHsiaFlows(cntx context.Context) {
275 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530276 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
277 vs.triggerServiceFailureInd(statusCode, statusMessage)
278 }
279
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530280 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530281 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
282 vs.triggerServiceFailureInd(statusCode, statusMessage)
283 }
284}
285
286// AddUsHsiaFlows - Add US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530287func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530288
289 if vs.DeleteInProgress || vs.UpdateInProgress {
290 logger.Errorw(ctx, "Ignoring US HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
291 return nil
292 }
293
294 va := GetApplication()
295 logger.Infow(ctx, "Configuring US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
296 if !vs.UsHSIAFlowsApplied || vgcRebooted {
297 device, err := va.GetDeviceFromPort(vs.Port)
298 if err != nil {
299 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
300 return errorCodes.ErrDeviceNotFound
301 } else if device.State != controller.DeviceStateUP {
302 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
303 return nil
304 }
305
306 vs.Device = device.Name
307 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
308 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
309
310 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
311 pBits := vs.Pbits
312
313 //If no pbits configured for service, hence add PbitNone for flows
314 if len(vs.Pbits) == 0 {
315 pBits = append(pBits, PbitMatchNone)
316 }
317 for _, pbits := range pBits {
318 usflows, err := vs.BuildUsHsiaFlows(pbits)
319 if err != nil {
320 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
321 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
322 vs.triggerServiceFailureInd(statusCode, statusMessage)
323 continue
324 }
325 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530326 if err := vs.AddFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530327 logger.Errorw(ctx, "Error adding HSIA US flows", log.Fields{"Reason": err.Error()})
328 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
329 vs.triggerServiceFailureInd(statusCode, statusMessage)
330 }
331 }
332 vs.UsHSIAFlowsApplied = true
333 logger.Infow(ctx, "Pushed US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
334 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530335 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530336 return nil
337}
338
339// AddDsHsiaFlows - Add DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530340func (vs *VoltService) AddDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530341 if vs.DeleteInProgress {
342 logger.Errorw(ctx, "Ignoring DS HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
343 return nil
344 }
345
346 va := GetApplication()
347 logger.Infow(ctx, "Configuring DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
348 if !vs.DsHSIAFlowsApplied || vgcRebooted {
349 device, err := va.GetDeviceFromPort(vs.Port)
350 if err != nil {
351 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
352 return errorCodes.ErrDeviceNotFound
353 } else if device.State != controller.DeviceStateUP {
354 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
355 return nil
356 }
357
358 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
359 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
360
361 //If no pbits configured for service, hence add PbitNone for flows
362 if len(vs.DsRemarkPbitsMap) == 0 {
363 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
364 if err != nil {
365 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
366 return err
367 }
368 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530369 if err = vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530370 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
371 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
372 vs.triggerServiceFailureInd(statusCode, statusMessage)
373 }
374 } else {
375 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
376 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
377 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
378 if err != nil {
379 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
380 return err
381 }
382 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
383 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530384 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530385 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
386 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
387 vs.triggerServiceFailureInd(statusCode, statusMessage)
388 }
389 } else {
390 for matchPbit := range vs.DsRemarkPbitsMap {
391 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
392 if err != nil {
393 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
394 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
395 vs.triggerServiceFailureInd(statusCode, statusMessage)
396 continue
397 }
398 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530399 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530400 logger.Errorw(ctx, "Failed to Add HSIA DS flows", log.Fields{"Reason": err})
401 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
402 vs.triggerServiceFailureInd(statusCode, statusMessage)
403 }
404 }
405 }
406 }
407 vs.DsHSIAFlowsApplied = true
408 logger.Infow(ctx, "Pushed DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
409 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530410 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530411 return nil
412}
413
414// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530415func (vs *VoltService) DelUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530416
417 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Services": vs.Name})
418 if vs.UsHSIAFlowsApplied || vgcRebooted {
419 device, err := GetApplication().GetDeviceFromPort(vs.Port)
420 if err != nil {
421 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
422 return errorCodes.ErrDeviceNotFound
423 }
424
425 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
426 pBits := vs.Pbits
427
428 //If no pbits configured for service, hence add PbitNone for flows
429 if len(vs.Pbits) == 0 {
430 pBits = append(pBits, PbitMatchNone)
431 }
432 for _, pbits := range pBits {
433 usflows, err := vs.BuildUsHsiaFlows(pbits)
434 if err != nil {
435 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
436 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
437 vs.triggerServiceFailureInd(statusCode, statusMessage)
438 continue
439 }
440 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530441 if err = vs.DelFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530442 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
443 vs.triggerServiceFailureInd(statusCode, statusMessage)
444 }
445 }
446 vs.UsHSIAFlowsApplied = false
447 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530448 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530449 return nil
450}
451
452// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530453func (vs *VoltService) DelDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530454
455 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Services": vs.Name})
456 if vs.DsHSIAFlowsApplied || vgcRebooted {
457 device, err := GetApplication().GetDeviceFromPort(vs.Port)
458 if err != nil {
459 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
460 return errorCodes.ErrDeviceNotFound
461 }
462
463 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
464 var matchPbit int
465 //If no pbits configured for service, hence add PbitNone for flows
466 if len(vs.DsRemarkPbitsMap) == 0 {
467 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
468 if err != nil {
469 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
470 return err
471 }
472 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530473 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530474 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
475 vs.triggerServiceFailureInd(statusCode, statusMessage)
476 }
477 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
478 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
479 if err != nil {
480 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
481 return err
482 }
483 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530484 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530485 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
486 vs.triggerServiceFailureInd(statusCode, statusMessage)
487 }
488 } else {
489 for matchPbit = range vs.DsRemarkPbitsMap {
490 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
491 if err != nil {
492 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
493 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
494 vs.triggerServiceFailureInd(statusCode, statusMessage)
495 continue
496 }
497 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530498 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530499 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
500 vs.triggerServiceFailureInd(statusCode, statusMessage)
501 }
502 }
503 }
504 vs.DsHSIAFlowsApplied = false
505 }
506 logger.Infow(ctx, "Deleted HSIA DS flows from DB successfuly", log.Fields{"ServiceName": vs.Name})
507 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530508 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530509 return nil
510}
511
512// BuildDsHsiaFlows build the DS HSIA flows
513// Called for add/delete HSIA flows
514func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
515 flow := &of.VoltFlow{}
516 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
517
518 // Get the out and in ports for the flows
519 device, err := GetApplication().GetDeviceFromPort(vs.Port)
520 if err != nil {
521 return nil, errorCodes.ErrDeviceNotFound
522 }
523 inport, _ := GetApplication().GetPortID(device.NniPort)
524 outport, _ := GetApplication().GetPortID(vs.Port)
525 // PortName and PortID to be used for validation of port before flow pushing
526 flow.PortID = outport
527 flow.PortName = vs.Port
528 allowTransparent := 0
529 if vs.AllowTransparent {
530 allowTransparent = 1
531 }
532
533 // initialized actnPbit to 0 for cookie genration backward compatibility.
534 var actnPbit of.PbitType
535 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
536
537 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
538 //| 12-bit cvlan/UniVlan | 4 bits action pbit | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
539 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
540 cookie = cookie | of.DsFlowMask
541 cookie = cookie + (valToShift << 4) + uint64(pbits)
542 return cookie
543 }
544
545 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
546 if err != nil {
547 logger.Errorw(ctx, "DS HSIA flow push failed: Invalid SvlanTpid", log.Fields{"SvlanTpid": vs.SVlanTpid, "Service": vs.Name})
548 return nil, err
549 }
550
551 // Add Table-0 flow that deals with the outer VLAN in pOLT
552 {
553 subflow1 := of.NewVoltSubFlow()
554 subflow1.SetTableID(0)
555 subflow1.SetGoToTable(1)
556 subflow1.SetInPort(inport)
557
558 if pbits != PbitMatchNone {
559 subflow1.SetMatchPbit(pbits)
560 }
561
562 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
563 subflow1.SetPcp(of.PbitType(remarkPbit))
564 // match & action pbits are different, set remark-pbit action
565 actnPbit = of.PbitType(remarkPbit)
566 // mask remark p-bit to 4bits
567 actnPbit = actnPbit & 0x0F
568 }
569
570 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
571 return nil, err
572 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530573 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530574 if NonZeroMacAddress(vs.MacAddr) {
575 subflow1.SetMatchDstMac(vs.MacAddr)
576 }
577 subflow1.Priority = of.HsiaFlowPriority
578 subflow1.SetMeterID(vs.DsMeterID)
579
580 /* WriteMetaData 8 Byte(uint64) usage:
581 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
582 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
583 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
584 subflow1.SetWriteMetadata(metadata)
585
586 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
587 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
588 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
589 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
590
591 //TODO-COMM:
592 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
593 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
594 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
595 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
596
597 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
598 subflow1.SetTableMetadata(metadata)
599 // TODO - We are using cookie as key and must come up with better cookie
600 // allocation algorithm
601 /**
602 * Cokies may clash when -
603 * on same uni-port we have two sub-service
604 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
605 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
606 * However, this p-bit re-use will not be allowed by sub-mgr.
607 */
608 if vs.VlanControl == OLTCVlanOLTSVlan {
609 /**
610 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
611 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
612 * use old cookie.
613 */
614 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
615 if vgcRebooted {
616 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
617 }
618 } else {
619 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
620 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
621 }
622
623 flow.SubFlows[subflow1.Cookie] = subflow1
624 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
625 "subflow": subflow1})
626 }
627
628 //Add Table-1 flow that deals with inner VLAN at the ONU
629 {
630 subflow2 := of.NewVoltSubFlow()
631 subflow2.SetTableID(1)
632 subflow2.SetInPort(inport)
633 if NonZeroMacAddress(vs.MacAddr) {
634 subflow2.SetMatchDstMac(vs.MacAddr)
635 }
636
637 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
638 return nil, err
639 }
640 if pbits != PbitMatchNone {
641 subflow2.SetMatchPbit(pbits)
642 }
643
644 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
645 subflow2.SetPcp(of.PbitType(remarkPbit))
646 }
647
648 subflow2.SetOutPort(outport)
649 subflow2.SetMeterID(vs.DsMeterID)
650
651 // refer Table-0 flow generation for byte information
652 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
653 subflow2.SetWriteMetadata(metadata)
654
655 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
656 if util.IsNniPort(inport) {
657 metadata = uint64(outport)
658 } else {
659 // refer Table-0 flow generation for byte information
660 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
661 }
662 subflow2.SetTableMetadata(metadata)
663 // Setting of Cookie - TODO - Improve the allocation algorithm
664 if vs.VlanControl == OLTCVlanOLTSVlan {
665 /**
666 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
667 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
668 * use old cookie.
669 */
670 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
671 if vgcRebooted {
672 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
673 }
674 } else {
675 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
676 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
677 }
678
679 subflow2.Priority = of.HsiaFlowPriority
680 flow.SubFlows[subflow2.Cookie] = subflow2
681 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
682 "subflow": subflow2})
683 }
684
685 return flow, nil
686}
687
688// BuildUsHsiaFlows build the US HSIA flows
689// Called for add/delete HSIA flows
690func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
691 flow := &of.VoltFlow{}
692 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
693
694 // Get the out and in ports for the flows
695 device, err := GetApplication().GetDeviceFromPort(vs.Port)
696 if err != nil {
697 return nil, errorCodes.ErrDeviceNotFound
698 }
699 outport, _ := GetApplication().GetPortID(device.NniPort)
700 inport, _ := GetApplication().GetPortID(vs.Port)
701 // PortName and PortID to be used for validation of port before flow pushing
702 flow.PortID = inport
703 flow.PortName = vs.Port
704 allowTransparent := 0
705 reqBwInfo := 0
706 if vs.AllowTransparent {
707 allowTransparent = 1
708 }
709 if vs.BwAvailInfo == "" {
710 reqBwInfo = 1
711 }
712
713 // Add Table-0 flow that deals with the inner VLAN in ONU
714 {
715 subflow1 := of.NewVoltSubFlow()
716 subflow1.SetTableID(0)
717 subflow1.SetGoToTable(1)
718 subflow1.SetInPort(inport)
719
720 if pbits != PbitMatchNone {
721 subflow1.SetMatchPbit(pbits)
722 }
723 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
724 return nil, err
725 }
726 subflow1.SetMeterID(vs.UsMeterID)
727
728 /* WriteMetaData 8 Byte(uint64) usage:
729 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
730 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
731 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
732 subflow1.SetWriteMetadata(metadata)
733
734 /* TableMetaData 8 Byte(uint64) usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
735 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
736 | 000 | 0 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
737 | reserved | reqBwInfo | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
738 metadata = uint64(reqBwInfo)<<60 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
739
740 // // In case of MAC Learning enabled voltha will buffer the US flow installation.
741 // if NonZeroMacAddress(vs.MacAddr) {
742 // subflow1.SetMatchSrcMac(vs.MacAddr)
743 // } else if vs.MacLearning != MacLearning {
744 // metadata |= 1 << 57
745 // logger.Infow(ctx, "Buffer us flow at adapter", log.Fields{"metadata": metadata})
746 // }
747 subflow1.SetTableMetadata(metadata)
748 if vs.VlanControl == OLTCVlanOLTSVlan {
749 /**
750 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
751 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
752 * use old cookie.
753 */
754 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
755 if vgcRebooted {
756 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
757 }
758 } else {
759 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
760 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
761 }
762 subflow1.Priority = of.HsiaFlowPriority
763 flow.SubFlows[subflow1.Cookie] = subflow1
764 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
765 }
766
767 //Add Table-1 flow that deals with the outer vlan in pOLT
768 {
769 subflow2 := of.NewVoltSubFlow()
770 subflow2.SetTableID(1)
771 subflow2.SetInPort(inport)
772
773 if pbits != PbitMatchNone {
774 subflow2.SetMatchPbit(pbits)
775 }
776
777 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
778 return nil, err
779 }
780 subflow2.SetInPort(inport)
781 subflow2.SetOutPort(outport)
782 subflow2.SetMeterID(vs.UsMeterID)
783
784 // refer Table-0 flow generation for byte information
785 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
786 subflow2.SetWriteMetadata(metadata)
787
788 // refer Table-0 flow generation for byte information
789 metadata = uint64(reqBwInfo)<<60 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
790 // // In case of MAC Learning enabled voltha will buffer the US flow installation.
791 // if NonZeroMacAddress(vs.MacAddr) {
792 // subflow2.SetMatchSrcMac(vs.MacAddr)
793 // } else if vs.MacLearning != MacLearningNone {
794 // metadata |= 1 << 57
795 // logger.Infow(ctx, "Buffer us flow at adapter", log.Fields{"metadata": metadata})
796 // }
797 subflow2.SetTableMetadata(metadata)
798 if vs.VlanControl == OLTCVlanOLTSVlan {
799 /**
800 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
801 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
802 * use old cookie.
803 */
804 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
805 if vgcRebooted {
806 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
807 }
808 } else {
809 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
810 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
811 }
812 subflow2.Priority = of.HsiaFlowPriority
813
814 flow.SubFlows[subflow2.Cookie] = subflow2
815 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
816 }
817
818 return flow, nil
819}
820
821func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
822 //| 12-bit cvlan/UniVlan | 4 bits empty | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
823 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
824 cookie = cookie | of.UsFlowMask
825 cookie = cookie + (valToShift << 4) + uint64(pbits)
826 return cookie
827}
828
829// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
830// based on different Vlan Controls
831func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
832 switch vs.VlanControl {
833 case None:
834 flow.SetMatchVlan(vs.SVlan)
835 case ONUCVlanOLTSVlan:
836 flow.SetMatchVlan(vs.CVlan)
837 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
838 case OLTCVlanOLTSVlan:
839 flow.SetMatchVlan(vs.UniVlan)
840 flow.SetSetVlan(vs.CVlan)
841 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
842 case ONUCVlan:
843 flow.SetMatchVlan(vs.SVlan)
844 case OLTSVlan:
845 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
846 flow.SetMatchVlan(vs.UniVlan)
847 flow.SetSetVlan(vs.SVlan)
848 } else if vs.UniVlan != of.VlanNone {
849 flow.SetMatchVlan(vs.UniVlan)
850 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
851 } else {
852 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
853 }
854 default:
855 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
856 return errorCodes.ErrInvalidParamInRequest
857 }
858 return nil
859}
860
861// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
862// based on different Vlan Controls
863func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
864 switch vs.VlanControl {
865 case None:
866 flow.SetMatchVlan(vs.SVlan)
867 case ONUCVlanOLTSVlan:
868 flow.SetMatchVlan(vs.SVlan)
869 flow.SetPopVlan()
870 case OLTCVlanOLTSVlan:
871 flow.SetMatchVlan(vs.SVlan)
872 flow.SetPopVlan()
873 flow.SetSetVlan(vs.UniVlan)
874 case ONUCVlan:
875 flow.SetMatchVlan(vs.SVlan)
876 case OLTSVlan:
877 flow.SetMatchVlan(vs.SVlan)
878 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
879 flow.SetSetVlan(vs.UniVlan)
880 } else {
881 flow.SetPopVlan()
882 }
883 default:
884 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
885 return errorCodes.ErrInvalidParamInRequest
886 }
887 return nil
888}
889
890// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
891// based on different Vlan Controls
892func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
893 switch vs.VlanControl {
894 case None:
895 flow.SetMatchVlan(vs.SVlan)
896 case ONUCVlanOLTSVlan:
897 if vs.UniVlan != of.VlanNone {
898 flow.SetMatchVlan(vs.UniVlan)
899 flow.SetSetVlan(vs.CVlan)
900 } else {
901 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
902 }
903 case OLTCVlanOLTSVlan:
904 flow.SetMatchVlan(vs.UniVlan)
905 case ONUCVlan:
906 if vs.UniVlan != of.VlanNone {
907 flow.SetMatchVlan(vs.UniVlan)
908 flow.SetSetVlan(vs.SVlan)
909 } else {
910 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
911 }
912 case OLTSVlan:
913 flow.SetMatchVlan(vs.UniVlan)
914 default:
915 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
916 return errorCodes.ErrInvalidParamInRequest
917 }
918 return nil
919}
920
921// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
922// based on different Vlan Controls
923func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
924 switch vs.VlanControl {
925 case None:
926 flow.SetMatchVlan(vs.SVlan)
927 case ONUCVlanOLTSVlan:
928 flow.SetMatchVlan(vs.CVlan)
929 if vs.UniVlan != of.VlanNone {
930 flow.SetSetVlan(vs.UniVlan)
931 } else {
932 flow.SetPopVlan()
933 }
934 case OLTCVlanOLTSVlan:
935 flow.SetMatchVlan(vs.UniVlan)
936 case ONUCVlan:
937 flow.SetMatchVlan(vs.SVlan)
938 if vs.UniVlan != of.VlanNone {
939 flow.SetSetVlan(vs.UniVlan)
940 } else {
941 flow.SetPopVlan()
942 }
943 case OLTSVlan:
944 flow.SetMatchVlan(vs.UniVlan)
945 default:
946 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
947 return errorCodes.ErrInvalidParamInRequest
948 }
949 return nil
950}
951
952// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530953func (vs *VoltService) SvcUpInd(cntx context.Context) {
954 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530955}
956
957// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530958func (vs *VoltService) SvcDownInd(cntx context.Context) {
959 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530960}
961
962// SetIpv4Addr to set ipv4 address
963func (vs *VoltService) SetIpv4Addr(addr net.IP) {
964 vs.Ipv4Addr = addr
965}
966
967// SetIpv6Addr to set ipv6 address
968func (vs *VoltService) SetIpv6Addr(addr net.IP) {
969 vs.Ipv6Addr = addr
970}
971
972// SetMacAddr to set mac address
973func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
974 vs.MacAddr = addr
975}
976
977// ----------------------------------------------
978// VOLT Application - Related to services
979// ---------------------------------------------
980// ---------------------------------------------------------------
981// Service CRUD functions. These are exposed to the overall binary
982// to be invoked from the point where the CRUD operations are received
983// from the external entities
984
985// AddService : A service in the context of VOLT is a subscriber or service of a
986// subscriber which is uniquely identified by a combination of MAC
987// address, VLAN tags, 802.1p bits. However, in the context of the
988// current implementation, a service is an entity that is identified by a
989// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
990// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530991func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530992 var mmUs, mmDs *VoltMeter
993 var err error
994
995 //Take the Device lock only in case of NB add request.
996 // Allow internal adds since internal add happen only under
997 // 1. Restore Service from DB
998 // 2. Service Migration
999 if oper == nil {
1000 if svc := va.GetService(cfg.Name); svc != nil {
1001 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
1002 return errors.New("Service Already Exists")
1003 }
1004 }
1005
1006 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
1007 // Service doesn't exist. So create it and add to the port
1008 vs := NewVoltService(&cfg)
1009 if oper != nil {
1010 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1011 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1012 vs.Ipv4Addr = oper.Ipv4Addr
1013 vs.Ipv6Addr = oper.Ipv6Addr
1014 vs.MacLearning = cfg.MacLearning
1015 vs.PendingFlows = oper.PendingFlows
1016 vs.AssociatedFlows = oper.AssociatedFlows
1017 vs.DeleteInProgress = oper.DeleteInProgress
1018 vs.BwAvailInfo = oper.BwAvailInfo
1019 vs.Device = oper.Device
1020 } else {
1021
1022 //Sorting Pbit from highest
1023 sort.Slice(vs.Pbits, func(i, j int) bool {
1024 return vs.Pbits[i] > vs.Pbits[j]
1025 })
1026 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1027 }
1028 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1029
1030 // The bandwidth and shaper profile combined into meter
1031 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1032 vs.DsMeterID = mmDs.ID
1033 } else {
1034 return errors.New("DownStream meter profile not found")
1035 }
1036
1037 // The aggregated downstream meter profile
1038 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1039 // vs.AggDsMeterID = mmAg.ID
1040 // } else {
1041 // return errors.New("Aggregated meter profile not found")
1042 // }
1043
1044 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1045 // vs.UsMeterID = mmAg.ID
1046 // } else {
1047 // The bandwidth and shaper profile combined into meter
1048 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1049 vs.UsMeterID = mmUs.ID
1050 } else {
1051 return errors.New("Upstream meter profile not found")
1052 }
1053 //}
1054
1055 AppMutex.ServiceDataMutex.Lock()
1056 defer AppMutex.ServiceDataMutex.Unlock()
1057
1058 // Add the service to the VNET
1059 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1060 if vnet != nil {
1061 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1062 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301063 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301064 vpv.VpvLock.Unlock()
1065 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301066 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301067 }
1068 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301069 logger.Errorw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301070 return errors.New("VNET doesn't exist")
1071 }
1072
1073 vs.Version = database.PresentVersionMap[database.ServicePath]
1074 // Add the service to the volt application
1075 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301076 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301077
1078 if nil == oper {
1079
1080 if !vs.UsHSIAFlowsApplied {
1081 vs.triggerServiceInProgressInd()
1082 }
1083
1084 //Update meter profiles service count if service is being added from northbound
1085 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301086 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301087 if mmUs != nil {
1088 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301089 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301090 }
1091 //mmAg.AssociatedServices++
1092 //va.UpdateMeterProf(*mmAg)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301093 logger.Debugw(ctx, "northbound-service-add-sucessful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301094 }
1095
1096 logger.Warnw(ctx, "Added Service to DB", log.Fields{"Name": vs.Name, "Port": (vs.Port), "ML": vs.MacLearning})
1097 return nil
1098}
1099
1100//DelServiceWithPrefix - Deletes service with the provided prefix.
1101// Added for DT/TT usecase with sadis replica interface
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301102func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301103 va.ServiceByName.Range(func(key, value interface{}) bool {
1104 srvName := key.(string)
1105 vs := value.(*VoltService)
1106 if strings.Contains(srvName, prefix) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301107 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301108
1109 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1110 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1111 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1112
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301113 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301114 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1115 }
1116 }
1117 return true
1118 })
1119}
1120
1121// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301122func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301123
1124 AppMutex.ServiceDataMutex.Lock()
1125 defer AppMutex.ServiceDataMutex.Unlock()
1126
1127 logger.Warnw(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
1128 var noFlowsPresent bool
1129
1130 vsIntf, ok := va.ServiceByName.Load(name)
1131 if !ok {
1132 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1133 return
1134 }
1135 vs := vsIntf.(*VoltService)
1136 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1137 if vpv == nil {
1138 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
1139 return
1140 }
1141
1142 //Set this to avoid race-condition during flow result processing
1143 vs.DeleteInProgress = true
1144 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301145 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301146
1147 if len(vs.AssociatedFlows) == 0 {
1148 noFlowsPresent = true
1149 }
1150 vpv.VpvLock.Lock()
1151 defer vpv.VpvLock.Unlock()
1152
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301153 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301154
1155 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301156 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301157 }
1158 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 +05301159 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301160 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301161 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301162 }
1163
1164 // Delete the service immediately in case of Force Delete
1165 // This will be enabled when profile reconciliation happens after restore
1166 // of backedup data
1167 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301168 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301169 GetApplication().ServiceByName.Delete(vs.Name)
1170 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1171 }
1172
1173 meterProfiles := make(map[*VoltMeter]bool)
1174
1175 if nil != newSvc {
1176 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1177 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1178 }
1179 skipMeterDeletion := false
1180 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1181 if nil != newSvc && aggMeter.Name == newSvc.AggDsMeterProfile {
1182 skipMeterDeletion = true
1183 }
1184
1185 meterProfiles[aggMeter] = skipMeterDeletion
1186 skipMeterDeletion = false
1187 }
1188 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
1189 if nil != newSvc && dsMeter.Name == newSvc.DsMeterProfile {
1190 skipMeterDeletion = true
1191 }
1192 meterProfiles[dsMeter] = skipMeterDeletion
1193 skipMeterDeletion = false
1194 }
1195 if vs.AggDsMeterID != vs.UsMeterID {
1196 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
1197 if nil != newSvc && usMeter.Name == newSvc.UsMeterProfile {
1198 skipMeterDeletion = true
1199 }
1200 meterProfiles[usMeter] = skipMeterDeletion
1201 }
1202 }
1203
1204 for meter, skipMeterDeletion := range meterProfiles {
1205 if nil == meter {
1206 logger.Debug(ctx, "Null meter found, continuing")
1207 continue
1208 }
1209 if meter.AssociatedServices > 0 {
1210 meter.AssociatedServices--
1211 if meter.AssociatedServices == 0 && !skipMeterDeletion {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301212 logger.Infow(ctx, "Meter should be deleted now\n", log.Fields{"MeterID": meter})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301213 va.UpdateMeterProf(cntx, *meter)
Naveen Sampath04696f72022-06-13 15:19:14 +05301214 }
1215 }
1216 }
1217
1218 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301219 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301220 }
1221
1222 //Delete the per service counter too
1223 va.ServiceCounters.Delete(name)
1224 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301225 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301226 }
1227}
1228
1229//AddFlows - Adds the flow to the service
1230// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301231func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301232
1233 // Using locks instead of concurrent map for PendingFlows to avoid
1234 // race condition during flow response indication processing
1235 vs.ServiceLock.Lock()
1236 defer vs.ServiceLock.Unlock()
1237
1238 for cookie := range flow.SubFlows {
1239 cookie := strconv.FormatUint(cookie, 10)
1240 fe := &FlowEvent{
1241 eType: EventTypeServiceFlowAdded,
1242 device: device.Name,
1243 cookie: cookie,
1244 eventData: vs,
1245 }
1246 device.RegisterFlowAddEvent(cookie, fe)
1247 vs.PendingFlows[cookie] = true
1248 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301249 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301250}
1251
1252//FlowInstallSuccess - Called when corresponding service flow installation is success
1253// If no more pending flows, HSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301254func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301255 if vs.DeleteInProgress {
1256 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1257 return
1258 }
1259 vs.ServiceLock.Lock()
1260
1261 if _, ok := vs.PendingFlows[cookie]; !ok {
1262 logger.Errorw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1263 vs.ServiceLock.Unlock()
1264 return
1265 }
1266
1267 delete(vs.PendingFlows, cookie)
1268 vs.AssociatedFlows[cookie] = true
1269 vs.ServiceLock.Unlock()
1270 var prevBwAvail, presentBwAvail string
1271 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1272 prevBwAvail = bwAvailInfo.PrevBw
1273 presentBwAvail = bwAvailInfo.PresentBw
1274 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301275 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301276 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301277 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301278
1279 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
1280
1281 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1282 if err != nil {
1283 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1284 return
1285 } else if device.State != controller.DeviceStateUP {
1286 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1287 return
1288 }
1289
1290 if vs.Trigger == ServiceVlanUpdate {
1291 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301292 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301293 }
1294 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1295 return
1296 }
1297 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1298}
1299
1300//FlowInstallFailure - Called when corresponding service flow installation is failed
1301// Trigger service failure indication to NB
1302func (vs *VoltService) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
1303 vs.ServiceLock.RLock()
1304
1305 if _, ok := vs.PendingFlows[cookie]; !ok {
1306 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1307 vs.ServiceLock.RUnlock()
1308 return
1309 }
1310 vs.ServiceLock.RUnlock()
1311 logger.Errorw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1312 vs.triggerServiceFailureInd(errorCode, errReason)
1313}
1314
1315//DelFlows - Deletes the flow from the service
1316// Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301317func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301318
1319 if !vs.ForceDelete {
1320 // Using locks instead of concurrent map for AssociatedFlows to avoid
1321 // race condition during flow response indication processing
1322 vs.ServiceLock.Lock()
1323 defer vs.ServiceLock.Unlock()
1324
1325 for cookie := range flow.SubFlows {
1326 cookie := strconv.FormatUint(cookie, 10)
1327 fe := &FlowEvent{
1328 eType: EventTypeServiceFlowRemoved,
1329 cookie: cookie,
1330 eventData: vs,
1331 }
1332 device.RegisterFlowDelEvent(cookie, fe)
1333 }
1334 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301335 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301336}
1337
1338//CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301339func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301340 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301341 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301342 GetApplication().ServiceByName.Delete(vs.Name)
1343 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1344 }
1345}
1346
1347//FlowRemoveSuccess - Called when corresponding service flow removal is success
1348// If no more associated flows, DelHSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301349func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301350
1351 // if vs.DeleteInProgress {
1352 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1353 // return
1354 // }
1355 vs.ServiceLock.Lock()
1356 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1357
1358 if _, ok := vs.AssociatedFlows[cookie]; ok {
1359 delete(vs.AssociatedFlows, cookie)
1360 } else if _, ok := vs.PendingFlows[cookie]; ok {
1361 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})
1362 } else {
1363 logger.Errorw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
1364 }
1365
1366 vs.ServiceLock.Unlock()
1367
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301368 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301369
1370 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
1371
1372 device := GetApplication().GetDevice(vs.Device)
1373 if device == nil {
1374 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1375 return
1376 } else if device.State != controller.DeviceStateUP {
1377 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1378 return
1379 }
1380
1381 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301382 vs.updateVnetProfile(cntx, vs.Device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301383 //Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
1384 return
1385 }
1386 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 +05301387 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301388
1389 return
1390 }
1391 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1392}
1393
1394//FlowRemoveFailure - Called when corresponding service flow installation is failed
1395// Trigger service failure indication to NB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301396func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301397 vs.ServiceLock.RLock()
1398
1399 if _, ok := vs.AssociatedFlows[cookie]; !ok {
1400 logger.Errorw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1401 vs.ServiceLock.RUnlock()
1402 return
1403 }
1404 if vs.DeleteInProgress {
1405 delete(vs.AssociatedFlows, cookie)
1406 }
1407 vs.ServiceLock.RUnlock()
1408 logger.Errorw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1409
1410 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301411 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301412}
1413
1414func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
1415 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1416 if err != nil {
1417 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1418 return
1419 } else if device.State != controller.DeviceStateUP {
1420 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1421 return
1422 }
1423}
1424
1425// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301426func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301427 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301428 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301429 for _, vs := range vss {
1430 b, ok := vs.Value.([]byte)
1431 if !ok {
1432 logger.Warn(ctx, "The value type is not []byte")
1433 continue
1434 }
1435 var vvs VoltService
1436 err := json.Unmarshal(b, &vvs)
1437 if err != nil {
1438 logger.Warn(ctx, "Unmarshal of VNET failed")
1439 continue
1440 }
1441 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301442 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301443 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1444 }
1445
1446 if vvs.VoltServiceOper.DeleteInProgress {
1447 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1448 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1449 }
1450 }
1451}
1452
1453// GetService to get service
1454func (va *VoltApplication) GetService(name string) *VoltService {
1455 if vs, ok := va.ServiceByName.Load(name); ok {
1456 return vs.(*VoltService)
1457 }
1458 return nil
1459}
1460
1461// GetCircuitID to get circuit id
1462func (vs *VoltService) GetCircuitID() []byte {
1463 return []byte(vs.CircuitID)
1464}
1465
1466// GetRemoteID to get remote id
1467func (vs *VoltService) GetRemoteID() []byte {
1468 return []byte(vs.RemoteID)
1469}
1470
1471// IPAssigned to check if ip is assigned
1472func (vs *VoltService) IPAssigned() bool {
1473 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1474 return true
1475 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1476 return true
1477 }
1478 return false
1479}
1480
1481// GetServiceNameFromCookie to get service name from cookie
1482func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
1483
1484 var vlan uint64
1485 vlanControl := (tableMetadata >> 32) & 0xF
1486
1487 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1488 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1489 vlan = (tableMetadata >> 16) & 0xFFFF
1490 } else {
1491 //Fetching CVlan for other vlanControl
1492 vlan = cookie >> 52
1493 }
1494 logger.Infow(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
1495 var vlans []of.VlanType
1496 vlans = append(vlans, of.VlanType(vlan))
1497 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1498 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301499 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301500 } else {
1501 logger.Errorw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
1502 }
1503 return service
1504}
1505
1506//MigrateServicesReqStatus - update vnet request status
1507type MigrateServicesReqStatus string
1508
1509const (
1510 //MigrateSrvsReqInit constant
1511 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
1512 //MigrateSrvsReqDeactTriggered constant
1513 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
1514 //MigrateSrvsReqCompleted constant
1515 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1516)
1517
1518//MigrateServicesRequest - update vnet request params
1519type MigrateServicesRequest struct {
1520 ID string
1521 OldVnetID string
1522 NewVnetID string
1523 ServicesList map[string]bool
1524 DeviceID string
1525 Status MigrateServicesReqStatus
1526 MigrateServicesLock sync.RWMutex
1527}
1528
1529func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
1530
1531 var msr MigrateServicesRequest
1532 msr.OldVnetID = oldVnetID
1533 msr.NewVnetID = newVnetID
1534 msr.ID = id
1535 msr.ServicesList = serviceMap
1536 msr.DeviceID = deviceID
1537 msr.Status = MigrateSrvsReqInit
1538 return &msr
1539}
1540
1541//GetMsrKey - generates migrate service request key
1542func (msr *MigrateServicesRequest) GetMsrKey() string {
1543 return msr.OldVnetID + "-" + msr.ID
1544}
1545
1546// //isRequestComplete - return if all request has been processed and completed
1547// // RequestProcessed indicates that all the profile de-activation has been triggered
1548// // And the associated profiles indicates the profiles awaiting results
1549// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1550// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1551// return (len(edr.AssociatedProfiles) == 0)
1552// }
1553
1554//WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301555func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301556 logger.Debugw(ctx, "Adding Migrate Service Request to DB", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID, "Device": msr.DeviceID, "RequestID": msr.ID, "ServiceCount": len(msr.ServicesList)})
1557 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301558 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301559 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
1560 "Device": msr.DeviceID, "Error": err})
1561 }
1562 }
1563}
1564
1565//MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301566func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301567
1568 logger.Warnw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
1569 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
1570 return errors.New("Old Vnet Id not found")
1571 }
1572 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
1573 return errors.New("New Vnet Id not found")
1574 }
1575
1576 d := va.GetDeviceBySerialNo(serialNum)
1577 if d == nil {
1578 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1579 return errorCodes.ErrDeviceNotFound
1580 }
1581
1582 serviceMap := make(map[string]bool)
1583
1584 for _, service := range serviceList {
1585 serviceMap[service] = false
1586 }
1587 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301588 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301589
1590 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301591 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301592 return nil
1593}
1594
1595//ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301596func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301597 va := GetApplication()
1598 for srv, processed := range msr.ServicesList {
1599
1600 //Indicates new service is already created and only deletion of old one is pending
1601 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301602 va.DelService(cntx, srv, true, nil, true)
1603 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301604 continue
1605 }
1606
1607 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1608 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1609 vs := vsIntf.(*VoltService)
1610 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1611 if vpv == nil {
1612 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
1613 continue
1614 }
1615 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1616 vpv.Blocked = true
1617
1618 // setDeactTrigger := func(key, value interface{}) bool {
1619 // vs := value.(*VoltService)
1620 vs.ServiceLock.Lock()
1621 vs.UpdateInProgress = true
1622 metadata := &MigrateServiceMetadata{
1623 NewVnetID: msr.NewVnetID,
1624 RequestID: msr.ID,
1625 }
1626 vs.Metadata = metadata
1627 vs.ServiceLock.Unlock()
1628
1629 //vpv flows will be removed when last service is removed from it and
1630 // new vpv flows will be installed when new service is added
1631 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301632 vpv.DelTrapFlows(cntx)
1633 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301634 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301635 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301636 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301637 }
1638 } else {
1639 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1640 }
1641 }
1642}
1643
1644//AddMigratingServices - store msr info to device obj
1645func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
1646
1647 var msrMap *util.ConcurrentMap
1648 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1649 msrMap = util.NewConcurrentMap()
1650 } else {
1651 msrMap = msrMapIntf.(*util.ConcurrentMap)
1652 }
1653
1654 msrMap.Set(msr.ID, msr)
1655 logger.Infow(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
1656
1657 d.MigratingServices.Set(msr.OldVnetID, msrMap)
1658 logger.Infow(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
1659
1660}
1661
1662//getMigrateServicesRequest - fetches msr info from device
1663func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
1664 if vd := va.GetDevice(deviceID); vd != nil {
1665 logger.Infow(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
1666 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1667 msrList := msrListIntf.(*util.ConcurrentMap)
1668 logger.Infow(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
1669 if msrObj, ok := msrList.Get(requestID); ok {
1670 return msrObj.(*MigrateServicesRequest)
1671 }
1672
1673 }
1674 }
1675 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
1676 return nil
1677}
1678
1679//updateMigrateServicesRequest - Updates the device with updated msr
1680func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
1681 if vd := va.GetDevice(deviceID); vd != nil {
1682 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1683 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1684 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1685 }
1686 }
1687 }
1688}
1689
1690//updateVnetProfile - Called on flow process completion
1691// Removes old service and creates new VPV & service with udpated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301692func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301693
Tinoj Joseph1d108322022-07-13 10:07:39 +05301694 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 +05301695
1696 nvs := VoltService{}
1697 nvs.VoltServiceCfg = vs.VoltServiceCfg
1698 nvs.Device = vs.Device
1699 nvs.Ipv4Addr = vs.Ipv4Addr
1700 nvs.Ipv6Addr = vs.Ipv6Addr
1701 nvs.UsMeterID = vs.UsMeterID
1702 nvs.DsMeterID = vs.DsMeterID
1703 nvs.AggDsMeterID = vs.AggDsMeterID
1704 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1705 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1706 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1707 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1708 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1709 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1710 nvs.PendingFlows = vs.PendingFlows
1711 nvs.AssociatedFlows = vs.AssociatedFlows
1712 nvs.DeleteInProgress = vs.DeleteInProgress
1713 nvs.ForceDelete = vs.ForceDelete
1714 nvs.BwAvailInfo = vs.BwAvailInfo
1715 nvs.UpdateInProgress = vs.UpdateInProgress
1716
1717 if nvs.DeleteInProgress {
1718 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1719 return
1720 }
1721
1722 metadata := vs.Metadata.(*MigrateServiceMetadata)
1723 oldVnetID := vs.VnetID
1724 nvs.VnetID = metadata.NewVnetID
1725 id := metadata.RequestID
1726 oldSrvName := vs.Name
1727
1728 if metadata == nil || metadata.NewVnetID == "" {
1729 logger.Errorw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
1730 return
1731 }
1732
1733 //First add the new service and then only delete the old service
1734 // Since if post del service in case of pod crash or reboot, the service data will be lost
1735 va := GetApplication()
1736 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1737 vnets := strings.Split(metadata.NewVnetID, "-")
1738 svlan, _ := strconv.Atoi(vnets[0])
1739 nvs.SVlan = of.VlanType(svlan)
1740 nvs.UpdateInProgress = false
1741 nvs.Metadata = nil
1742 nvs.Trigger = ServiceVlanUpdate
1743
1744 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1745 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1746 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1747
1748 //TODO:Nav Pass a copy, not the pointer
1749 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 +05301750 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301751 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1752 }
1753 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1754
1755 msr.ServicesList[oldSrvName] = true
1756 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301757 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301758
1759 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 +05301760 va.DelService(cntx, oldSrvName, true, nil, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301761 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 +05301762 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301763}
1764
1765//serviceMigrated - called on successful service updation
1766// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301767func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301768
1769 msr.MigrateServicesLock.Lock()
1770 defer msr.MigrateServicesLock.Unlock()
1771
1772 delete(msr.ServicesList, serviceName)
1773
1774 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301775 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301776 return
1777 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301778 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301779 //TODO:Nav - Need for any Response to SubMgr?
1780}
1781
1782//TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301783func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1784 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301785}
1786
1787//FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301788func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301789
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301790 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301791 for _, msr := range msrList {
1792 b, ok := msr.Value.([]byte)
1793 if !ok {
1794 logger.Warn(ctx, "The value type is not []byte")
1795 continue
1796 }
1797 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301798 msrAction(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301799 logger.Warnw(ctx, "Triggering Pending Migrate Services Req", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID, "Device": device, "PendingProfiles": len(msr.ServicesList)})
1800
1801 }
1802}
1803
1804// createMigrateServicesFromString to create Service from string
1805func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
1806 var msr MigrateServicesRequest
1807 if err := json.Unmarshal(b, &msr); err == nil {
1808 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
1809
1810 } else {
1811 logger.Warn(ctx, "Unmarshal failed")
1812 }
1813 return &msr
1814}
1815
1816//storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301817func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301818 d := GetApplication().GetDevice(msr.DeviceID)
1819 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301820 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301821}
1822
1823//forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301824func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301825 for srv := range msr.ServicesList {
1826 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301827 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301828 }
1829 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301830 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301831}
1832
1833//DeepEqualServicecfg - checks if the given service cfgs are same
1834func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1835 if nvs.Name != evs.Name {
1836 return false
1837 }
1838 if nvs.UniVlan != evs.UniVlan {
1839 return false
1840 }
1841 if nvs.CVlan != evs.CVlan {
1842 return false
1843 }
1844 if nvs.SVlan != evs.SVlan {
1845 return false
1846 }
1847 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1848 return false
1849 }
1850 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1851 return false
1852 }
1853 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1854 return false
1855 }
1856 if nvs.TechProfileID != evs.TechProfileID {
1857 return false
1858 }
1859 if nvs.CircuitID != evs.CircuitID {
1860 return false
1861 }
1862 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1863 return false
1864 }
1865 if nvs.Port != evs.Port {
1866 return false
1867 }
1868 if nvs.PonPort != evs.PonPort {
1869 return false
1870 }
1871 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1872 return false
1873 }
1874 if nvs.IsOption82Disabled != evs.IsOption82Disabled {
1875 return false
1876 }
1877 if nvs.IgmpEnabled != evs.IgmpEnabled {
1878 return false
1879 }
1880 if nvs.McastService != evs.McastService {
1881 return false
1882 }
1883 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1884 return false
1885 }
1886 if nvs.UsMeterProfile != evs.UsMeterProfile {
1887 return false
1888 }
1889 if nvs.DsMeterProfile != evs.DsMeterProfile {
1890 return false
1891 }
1892 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
1893 return false
1894 }
1895 if nvs.VnetID != evs.VnetID {
1896 return false
1897 }
1898 if nvs.MvlanProfileName != evs.MvlanProfileName {
1899 return false
1900 }
1901 if nvs.RemoteIDType != evs.RemoteIDType {
1902 return false
1903 }
1904 if nvs.SchedID != evs.SchedID {
1905 return false
1906 }
1907 if nvs.AllowTransparent != evs.AllowTransparent {
1908 return false
1909 }
1910 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
1911 return false
1912 }
1913 if nvs.DataRateAttr != evs.DataRateAttr {
1914 return false
1915 }
1916 if nvs.MinDataRateUs != evs.MinDataRateUs {
1917 return false
1918 }
1919 if nvs.MinDataRateDs != evs.MinDataRateDs {
1920 return false
1921 }
1922 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
1923 return false
1924 }
1925 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
1926 return false
1927 }
1928
1929 return true
1930}
1931
1932//TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301933func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301934
1935 //Clear the Flows flag if already set
1936 //This case happens only in case of some race condition
1937 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301938 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301939 logger.Errorw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1940 }
1941 }
1942
1943 if vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301944 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301945 logger.Errorw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1946 }
1947 }
1948
1949 vs.ServiceLock.Lock()
1950 cookieList := []uint64{}
1951 for cookie := range vs.AssociatedFlows {
1952 cookieList = append(cookieList, convertToUInt64(cookie))
1953 }
1954 vs.ServiceLock.Unlock()
1955
1956 if len(cookieList) == 0 {
1957 return false
1958 }
1959
1960 //Trigger Flow Delete
1961 for _, cookie := range cookieList {
1962 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
1963 flow := &of.VoltFlow{}
1964 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1965 subFlow := of.NewVoltSubFlow()
1966 subFlow.Cookie = cookie
1967 flow.SubFlows[cookie] = subFlow
1968 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301969 if err := vs.DelFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301970 logger.Errorw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
1971 }
1972 }
1973 }
1974 return true
1975}
1976
1977//triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
1978func (vs *VoltService) triggerServiceInProgressInd() {
1979}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301980
1981// JsonMarshal wrapper function for json Marshal VoltService
1982func (vs *VoltService) JsonMarshal() ([]byte, error) {
1983 return json.Marshal(VoltService{
1984 VoltServiceCfg: vs.VoltServiceCfg,
1985 VoltServiceOper: VoltServiceOper{
1986 Device: vs.VoltServiceOper.Device,
1987 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
1988 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
1989 UsMeterID: vs.VoltServiceOper.UsMeterID,
1990 DsMeterID: vs.VoltServiceOper.DsMeterID,
1991 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
1992 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
1993 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
1994 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
1995 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
1996 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
1997 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
1998 PendingFlows: vs.VoltServiceOper.PendingFlows,
1999 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
2000 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2001 ForceDelete: vs.VoltServiceOper.ForceDelete,
2002 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2003 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2004 Metadata: vs.VoltServiceOper.Metadata,
2005 },
2006 })
2007}