blob: af903afece6bee81bfc0de88f1da0b4c603d21bc [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"
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.
54// - In general, 4096 is used as NO VLAN for all the above
55// SVlanTpid - SVlan Tag Protocl Identifier
56// 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
61// port. The converse is not always true
62// MacLearning - If MAC learning is turned on, the MAC address learned from the
63// the service activation is used in programming flows
64// 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 {
67 Name string
68 UniVlan of.VlanType
69 CVlan of.VlanType
70 SVlan of.VlanType
71 SVlanTpid layers.EthernetType
72 MacAddr net.HardwareAddr
73 Pbits []of.PbitType
74 DsRemarkPbitsMap map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
75 TechProfileID uint16
76 CircuitID string
77 RemoteID []byte
78 Port string
79 PonPort uint32
80 MacLearning MacLearningType
81 IsOption82Disabled bool
82 IgmpEnabled bool
83 McastService bool
84 ONTEtherTypeClassification int
85 VlanControl VlanControl
86 UsMeterProfile string
87 DsMeterProfile string
88 AggDsMeterProfile string
89 VnetID string
90 MvlanProfileName string
91 RemoteIDType string
92 SchedID int
93 AllowTransparent bool
94 EnableMulticastKPI bool
95 DataRateAttr string
96 MinDataRateUs uint32
97 MinDataRateDs uint32
98 MaxDataRateUs uint32
99 MaxDataRateDs uint32
Tinoj Josephec742f62022-09-29 19:11:10 +0530100 IsActivated bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530101 Trigger ServiceTrigger
102}
103
104// VoltServiceOper structure
105type VoltServiceOper struct {
106 //MacLearning bool
107 //MacAddr net.HardwareAddr
108 Device string
109 Ipv4Addr net.IP
110 Ipv6Addr net.IP
111
112 UsMeterID uint32
113 DsMeterID uint32
114 AggDsMeterID uint32
115
116 //Multiservice-Fix
117 UsHSIAFlowsApplied bool
118 DsHSIAFlowsApplied bool
119 UsDhcpFlowsApplied bool
120 DsDhcpFlowsApplied bool
121 IgmpFlowsApplied bool
122 Icmpv6FlowsApplied bool
123
124 ServiceLock sync.RWMutex `json:"-"`
125 PendingFlows map[string]bool
126 AssociatedFlows map[string]bool
127 DeleteInProgress bool
128 ForceDelete bool
129 BwAvailInfo string
130
131 UpdateInProgress bool
132 Metadata interface{}
133}
134
135// VoltService structure
136type VoltService struct {
137 VoltServiceCfg
138 VoltServiceOper
139 Version string
140}
141
142//ServiceTrigger - Service activation trigger
143type ServiceTrigger int
144
145const (
146 //NBActivate - Service added due to NB Action
147 NBActivate ServiceTrigger = 0
148 //ServiceVlanUpdate - Service added due to Svlan Update
149 ServiceVlanUpdate ServiceTrigger = 1
150)
151
152// AppMutexes structure
153type AppMutexes struct {
154 ServiceDataMutex sync.Mutex `json:"-"`
155 VnetMutex sync.Mutex `json:"-"`
156}
157
158//MigrateServiceMetadata - migrate services request metadata
159type MigrateServiceMetadata struct {
160 NewVnetID string
161 RequestID string
162}
163
164// AppMutex variable
165var AppMutex AppMutexes
166
167// NewVoltService for constructor for volt service
168func NewVoltService(cfg *VoltServiceCfg) *VoltService {
169 var vs VoltService
170 vs.VoltServiceCfg = *cfg
171 vs.UsHSIAFlowsApplied = false
172 vs.DsHSIAFlowsApplied = false
173 vs.DeleteInProgress = false
174 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
175
176 vs.MacAddr = cfg.MacAddr
177 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
178 vs.Ipv6Addr = net.ParseIP("::")
179 vs.PendingFlows = make(map[string]bool)
180 vs.AssociatedFlows = make(map[string]bool)
181 return &vs
182}
183
184// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530185func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530186
187 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
197//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})
218 //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
275//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
288// AddUsHsiaFlows - Add US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530289func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530290
291 if vs.DeleteInProgress || vs.UpdateInProgress {
292 logger.Errorw(ctx, "Ignoring US HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
293 return nil
294 }
295
296 va := GetApplication()
297 logger.Infow(ctx, "Configuring US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
298 if !vs.UsHSIAFlowsApplied || vgcRebooted {
299 device, err := va.GetDeviceFromPort(vs.Port)
300 if err != nil {
301 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
302 return errorCodes.ErrDeviceNotFound
303 } else if device.State != controller.DeviceStateUP {
304 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
305 return nil
306 }
307
308 vs.Device = device.Name
309 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
310 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
311
312 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
313 pBits := vs.Pbits
314
315 //If no pbits configured for service, hence add PbitNone for flows
316 if len(vs.Pbits) == 0 {
317 pBits = append(pBits, PbitMatchNone)
318 }
319 for _, pbits := range pBits {
320 usflows, err := vs.BuildUsHsiaFlows(pbits)
321 if err != nil {
322 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
323 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
324 vs.triggerServiceFailureInd(statusCode, statusMessage)
325 continue
326 }
327 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530328 if err := vs.AddFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530329 logger.Errorw(ctx, "Error adding HSIA US flows", log.Fields{"Reason": err.Error()})
330 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
331 vs.triggerServiceFailureInd(statusCode, statusMessage)
332 }
333 }
334 vs.UsHSIAFlowsApplied = true
335 logger.Infow(ctx, "Pushed US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
336 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530337 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530338 return nil
339}
340
341// AddDsHsiaFlows - Add DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530342func (vs *VoltService) AddDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530343 if vs.DeleteInProgress {
344 logger.Errorw(ctx, "Ignoring DS HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
345 return nil
346 }
347
348 va := GetApplication()
349 logger.Infow(ctx, "Configuring DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
350 if !vs.DsHSIAFlowsApplied || vgcRebooted {
351 device, err := va.GetDeviceFromPort(vs.Port)
352 if err != nil {
353 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
354 return errorCodes.ErrDeviceNotFound
355 } else if device.State != controller.DeviceStateUP {
356 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
357 return nil
358 }
359
360 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
361 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
362
363 //If no pbits configured for service, hence add PbitNone for flows
364 if len(vs.DsRemarkPbitsMap) == 0 {
365 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
366 if err != nil {
367 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
368 return err
369 }
370 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530371 if err = vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530372 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
373 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
374 vs.triggerServiceFailureInd(statusCode, statusMessage)
375 }
376 } else {
377 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
378 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
379 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
380 if err != nil {
381 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
382 return err
383 }
384 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
385 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530386 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530387 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
388 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
389 vs.triggerServiceFailureInd(statusCode, statusMessage)
390 }
391 } else {
392 for matchPbit := range vs.DsRemarkPbitsMap {
393 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
394 if err != nil {
395 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
396 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
397 vs.triggerServiceFailureInd(statusCode, statusMessage)
398 continue
399 }
400 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530401 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530402 logger.Errorw(ctx, "Failed to Add HSIA DS flows", log.Fields{"Reason": err})
403 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
404 vs.triggerServiceFailureInd(statusCode, statusMessage)
405 }
406 }
407 }
408 }
409 vs.DsHSIAFlowsApplied = true
410 logger.Infow(ctx, "Pushed DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
411 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530412 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530413 return nil
414}
415
416// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530417func (vs *VoltService) DelUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530418
419 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Services": vs.Name})
420 if vs.UsHSIAFlowsApplied || vgcRebooted {
421 device, err := GetApplication().GetDeviceFromPort(vs.Port)
422 if err != nil {
423 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
424 return errorCodes.ErrDeviceNotFound
425 }
426
427 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
428 pBits := vs.Pbits
429
430 //If no pbits configured for service, hence add PbitNone for flows
431 if len(vs.Pbits) == 0 {
432 pBits = append(pBits, PbitMatchNone)
433 }
434 for _, pbits := range pBits {
435 usflows, err := vs.BuildUsHsiaFlows(pbits)
436 if err != nil {
437 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
438 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
439 vs.triggerServiceFailureInd(statusCode, statusMessage)
440 continue
441 }
442 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530443 if err = vs.DelFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530444 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
445 vs.triggerServiceFailureInd(statusCode, statusMessage)
446 }
447 }
448 vs.UsHSIAFlowsApplied = false
449 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530450 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530451 return nil
452}
453
454// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530455func (vs *VoltService) DelDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530456
457 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Services": vs.Name})
458 if vs.DsHSIAFlowsApplied || vgcRebooted {
459 device, err := GetApplication().GetDeviceFromPort(vs.Port)
460 if err != nil {
461 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
462 return errorCodes.ErrDeviceNotFound
463 }
464
465 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
466 var matchPbit int
467 //If no pbits configured for service, hence add PbitNone for flows
468 if len(vs.DsRemarkPbitsMap) == 0 {
469 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
470 if err != nil {
471 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
472 return err
473 }
474 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530475 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530476 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
477 vs.triggerServiceFailureInd(statusCode, statusMessage)
478 }
479 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
480 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
481 if err != nil {
482 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
483 return err
484 }
485 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530486 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530487 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
488 vs.triggerServiceFailureInd(statusCode, statusMessage)
489 }
490 } else {
491 for matchPbit = range vs.DsRemarkPbitsMap {
492 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
493 if err != nil {
494 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
495 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
496 vs.triggerServiceFailureInd(statusCode, statusMessage)
497 continue
498 }
499 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530500 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530501 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
502 vs.triggerServiceFailureInd(statusCode, statusMessage)
503 }
504 }
505 }
506 vs.DsHSIAFlowsApplied = false
507 }
508 logger.Infow(ctx, "Deleted HSIA DS flows from DB successfuly", log.Fields{"ServiceName": vs.Name})
509 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530510 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530511 return nil
512}
513
514// BuildDsHsiaFlows build the DS HSIA flows
515// Called for add/delete HSIA flows
516func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
517 flow := &of.VoltFlow{}
518 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
519
520 // Get the out and in ports for the flows
521 device, err := GetApplication().GetDeviceFromPort(vs.Port)
522 if err != nil {
523 return nil, errorCodes.ErrDeviceNotFound
524 }
525 inport, _ := GetApplication().GetPortID(device.NniPort)
526 outport, _ := GetApplication().GetPortID(vs.Port)
527 // PortName and PortID to be used for validation of port before flow pushing
528 flow.PortID = outport
529 flow.PortName = vs.Port
530 allowTransparent := 0
531 if vs.AllowTransparent {
532 allowTransparent = 1
533 }
534
535 // initialized actnPbit to 0 for cookie genration backward compatibility.
536 var actnPbit of.PbitType
537 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
538
539 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
540 //| 12-bit cvlan/UniVlan | 4 bits action pbit | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
541 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
542 cookie = cookie | of.DsFlowMask
543 cookie = cookie + (valToShift << 4) + uint64(pbits)
544 return cookie
545 }
546
547 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
548 if err != nil {
549 logger.Errorw(ctx, "DS HSIA flow push failed: Invalid SvlanTpid", log.Fields{"SvlanTpid": vs.SVlanTpid, "Service": vs.Name})
550 return nil, err
551 }
552
553 // Add Table-0 flow that deals with the outer VLAN in pOLT
554 {
555 subflow1 := of.NewVoltSubFlow()
556 subflow1.SetTableID(0)
557 subflow1.SetGoToTable(1)
558 subflow1.SetInPort(inport)
559
560 if pbits != PbitMatchNone {
561 subflow1.SetMatchPbit(pbits)
562 }
563
564 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
565 subflow1.SetPcp(of.PbitType(remarkPbit))
566 // match & action pbits are different, set remark-pbit action
567 actnPbit = of.PbitType(remarkPbit)
568 // mask remark p-bit to 4bits
569 actnPbit = actnPbit & 0x0F
570 }
571
572 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
573 return nil, err
574 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530575 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530576 if NonZeroMacAddress(vs.MacAddr) {
577 subflow1.SetMatchDstMac(vs.MacAddr)
578 }
579 subflow1.Priority = of.HsiaFlowPriority
580 subflow1.SetMeterID(vs.DsMeterID)
581
582 /* WriteMetaData 8 Byte(uint64) usage:
583 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
584 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
585 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
586 subflow1.SetWriteMetadata(metadata)
587
588 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
589 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
590 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
591 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
592
593 //TODO-COMM:
594 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
595 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
596 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
597 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
598
599 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
600 subflow1.SetTableMetadata(metadata)
601 // TODO - We are using cookie as key and must come up with better cookie
602 // allocation algorithm
603 /**
604 * Cokies may clash when -
605 * on same uni-port we have two sub-service
606 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
607 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
608 * However, this p-bit re-use will not be allowed by sub-mgr.
609 */
610 if vs.VlanControl == OLTCVlanOLTSVlan {
611 /**
612 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
613 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
614 * use old cookie.
615 */
616 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
617 if vgcRebooted {
618 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
619 }
620 } else {
621 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
622 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
623 }
624
625 flow.SubFlows[subflow1.Cookie] = subflow1
626 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
627 "subflow": subflow1})
628 }
629
630 //Add Table-1 flow that deals with inner VLAN at the ONU
631 {
632 subflow2 := of.NewVoltSubFlow()
633 subflow2.SetTableID(1)
634 subflow2.SetInPort(inport)
635 if NonZeroMacAddress(vs.MacAddr) {
636 subflow2.SetMatchDstMac(vs.MacAddr)
637 }
638
639 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
640 return nil, err
641 }
642 if pbits != PbitMatchNone {
643 subflow2.SetMatchPbit(pbits)
644 }
645
646 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
647 subflow2.SetPcp(of.PbitType(remarkPbit))
648 }
649
650 subflow2.SetOutPort(outport)
651 subflow2.SetMeterID(vs.DsMeterID)
652
653 // refer Table-0 flow generation for byte information
654 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
655 subflow2.SetWriteMetadata(metadata)
656
657 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
658 if util.IsNniPort(inport) {
659 metadata = uint64(outport)
660 } else {
661 // refer Table-0 flow generation for byte information
662 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
663 }
664 subflow2.SetTableMetadata(metadata)
665 // Setting of Cookie - TODO - Improve the allocation algorithm
666 if vs.VlanControl == OLTCVlanOLTSVlan {
667 /**
668 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
669 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
670 * use old cookie.
671 */
672 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
673 if vgcRebooted {
674 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
675 }
676 } else {
677 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
678 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
679 }
680
681 subflow2.Priority = of.HsiaFlowPriority
682 flow.SubFlows[subflow2.Cookie] = subflow2
683 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
684 "subflow": subflow2})
685 }
686
687 return flow, nil
688}
689
690// BuildUsHsiaFlows build the US HSIA flows
691// Called for add/delete HSIA flows
692func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
693 flow := &of.VoltFlow{}
694 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
695
696 // Get the out and in ports for the flows
697 device, err := GetApplication().GetDeviceFromPort(vs.Port)
698 if err != nil {
699 return nil, errorCodes.ErrDeviceNotFound
700 }
701 outport, _ := GetApplication().GetPortID(device.NniPort)
702 inport, _ := GetApplication().GetPortID(vs.Port)
703 // PortName and PortID to be used for validation of port before flow pushing
704 flow.PortID = inport
705 flow.PortName = vs.Port
706 allowTransparent := 0
707 reqBwInfo := 0
708 if vs.AllowTransparent {
709 allowTransparent = 1
710 }
711 if vs.BwAvailInfo == "" {
712 reqBwInfo = 1
713 }
714
715 // Add Table-0 flow that deals with the inner VLAN in ONU
716 {
717 subflow1 := of.NewVoltSubFlow()
718 subflow1.SetTableID(0)
719 subflow1.SetGoToTable(1)
720 subflow1.SetInPort(inport)
721
Tinoj Josephec742f62022-09-29 19:11:10 +0530722 /*
Naveen Sampath04696f72022-06-13 15:19:14 +0530723 if pbits != PbitMatchNone {
724 subflow1.SetMatchPbit(pbits)
Tinoj Josephec742f62022-09-29 19:11:10 +0530725 }*/
Naveen Sampath04696f72022-06-13 15:19:14 +0530726 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
727 return nil, err
728 }
729 subflow1.SetMeterID(vs.UsMeterID)
730
731 /* WriteMetaData 8 Byte(uint64) usage:
732 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
733 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
734 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
735 subflow1.SetWriteMetadata(metadata)
736
737 /* TableMetaData 8 Byte(uint64) usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
738 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
739 | 000 | 0 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
740 | reserved | reqBwInfo | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
741 metadata = uint64(reqBwInfo)<<60 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
742
743 // // In case of MAC Learning enabled voltha will buffer the US flow installation.
744 // if NonZeroMacAddress(vs.MacAddr) {
745 // subflow1.SetMatchSrcMac(vs.MacAddr)
746 // } else if vs.MacLearning != MacLearning {
747 // metadata |= 1 << 57
748 // logger.Infow(ctx, "Buffer us flow at adapter", log.Fields{"metadata": metadata})
749 // }
750 subflow1.SetTableMetadata(metadata)
751 if vs.VlanControl == OLTCVlanOLTSVlan {
752 /**
753 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
754 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
755 * use old cookie.
756 */
757 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
758 if vgcRebooted {
759 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
760 }
761 } else {
762 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
763 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
764 }
765 subflow1.Priority = of.HsiaFlowPriority
766 flow.SubFlows[subflow1.Cookie] = subflow1
767 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
768 }
769
770 //Add Table-1 flow that deals with the outer vlan in pOLT
771 {
772 subflow2 := of.NewVoltSubFlow()
773 subflow2.SetTableID(1)
774 subflow2.SetInPort(inport)
775
776 if pbits != PbitMatchNone {
777 subflow2.SetMatchPbit(pbits)
778 }
779
780 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
781 return nil, err
782 }
783 subflow2.SetInPort(inport)
784 subflow2.SetOutPort(outport)
785 subflow2.SetMeterID(vs.UsMeterID)
786
787 // refer Table-0 flow generation for byte information
788 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
789 subflow2.SetWriteMetadata(metadata)
790
791 // refer Table-0 flow generation for byte information
792 metadata = uint64(reqBwInfo)<<60 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
793 // // In case of MAC Learning enabled voltha will buffer the US flow installation.
794 // if NonZeroMacAddress(vs.MacAddr) {
795 // subflow2.SetMatchSrcMac(vs.MacAddr)
796 // } else if vs.MacLearning != MacLearningNone {
797 // metadata |= 1 << 57
798 // logger.Infow(ctx, "Buffer us flow at adapter", log.Fields{"metadata": metadata})
799 // }
800 subflow2.SetTableMetadata(metadata)
801 if vs.VlanControl == OLTCVlanOLTSVlan {
802 /**
803 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
804 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
805 * use old cookie.
806 */
807 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
808 if vgcRebooted {
809 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
810 }
811 } else {
812 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
813 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
814 }
815 subflow2.Priority = of.HsiaFlowPriority
816
817 flow.SubFlows[subflow2.Cookie] = subflow2
818 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
819 }
820
821 return flow, nil
822}
823
824func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
825 //| 12-bit cvlan/UniVlan | 4 bits empty | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
826 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
827 cookie = cookie | of.UsFlowMask
828 cookie = cookie + (valToShift << 4) + uint64(pbits)
829 return cookie
830}
831
832// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
833// based on different Vlan Controls
834func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
835 switch vs.VlanControl {
836 case None:
837 flow.SetMatchVlan(vs.SVlan)
838 case ONUCVlanOLTSVlan:
839 flow.SetMatchVlan(vs.CVlan)
840 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
841 case OLTCVlanOLTSVlan:
842 flow.SetMatchVlan(vs.UniVlan)
843 flow.SetSetVlan(vs.CVlan)
844 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
845 case ONUCVlan:
846 flow.SetMatchVlan(vs.SVlan)
847 case OLTSVlan:
848 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
849 flow.SetMatchVlan(vs.UniVlan)
850 flow.SetSetVlan(vs.SVlan)
851 } else if vs.UniVlan != of.VlanNone {
852 flow.SetMatchVlan(vs.UniVlan)
853 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
854 } else {
855 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
856 }
857 default:
858 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
859 return errorCodes.ErrInvalidParamInRequest
860 }
861 return nil
862}
863
864// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
865// based on different Vlan Controls
866func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
867 switch vs.VlanControl {
868 case None:
869 flow.SetMatchVlan(vs.SVlan)
870 case ONUCVlanOLTSVlan:
871 flow.SetMatchVlan(vs.SVlan)
872 flow.SetPopVlan()
873 case OLTCVlanOLTSVlan:
874 flow.SetMatchVlan(vs.SVlan)
875 flow.SetPopVlan()
876 flow.SetSetVlan(vs.UniVlan)
877 case ONUCVlan:
878 flow.SetMatchVlan(vs.SVlan)
879 case OLTSVlan:
880 flow.SetMatchVlan(vs.SVlan)
881 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
882 flow.SetSetVlan(vs.UniVlan)
883 } else {
884 flow.SetPopVlan()
885 }
886 default:
887 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
888 return errorCodes.ErrInvalidParamInRequest
889 }
890 return nil
891}
892
893// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
894// based on different Vlan Controls
895func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
896 switch vs.VlanControl {
897 case None:
898 flow.SetMatchVlan(vs.SVlan)
899 case ONUCVlanOLTSVlan:
900 if vs.UniVlan != of.VlanNone {
901 flow.SetMatchVlan(vs.UniVlan)
902 flow.SetSetVlan(vs.CVlan)
903 } else {
904 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
905 }
906 case OLTCVlanOLTSVlan:
907 flow.SetMatchVlan(vs.UniVlan)
908 case ONUCVlan:
909 if vs.UniVlan != of.VlanNone {
910 flow.SetMatchVlan(vs.UniVlan)
911 flow.SetSetVlan(vs.SVlan)
912 } else {
913 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
914 }
915 case OLTSVlan:
916 flow.SetMatchVlan(vs.UniVlan)
917 default:
918 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
919 return errorCodes.ErrInvalidParamInRequest
920 }
921 return nil
922}
923
924// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
925// based on different Vlan Controls
926func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
927 switch vs.VlanControl {
928 case None:
929 flow.SetMatchVlan(vs.SVlan)
930 case ONUCVlanOLTSVlan:
931 flow.SetMatchVlan(vs.CVlan)
932 if vs.UniVlan != of.VlanNone {
933 flow.SetSetVlan(vs.UniVlan)
934 } else {
935 flow.SetPopVlan()
936 }
937 case OLTCVlanOLTSVlan:
938 flow.SetMatchVlan(vs.UniVlan)
939 case ONUCVlan:
940 flow.SetMatchVlan(vs.SVlan)
941 if vs.UniVlan != of.VlanNone {
942 flow.SetSetVlan(vs.UniVlan)
943 } else {
944 flow.SetPopVlan()
945 }
946 case OLTSVlan:
947 flow.SetMatchVlan(vs.UniVlan)
948 default:
949 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
950 return errorCodes.ErrInvalidParamInRequest
951 }
952 return nil
953}
954
955// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530956func (vs *VoltService) SvcUpInd(cntx context.Context) {
957 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530958}
959
960// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530961func (vs *VoltService) SvcDownInd(cntx context.Context) {
962 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530963}
964
965// SetIpv4Addr to set ipv4 address
966func (vs *VoltService) SetIpv4Addr(addr net.IP) {
967 vs.Ipv4Addr = addr
968}
969
970// SetIpv6Addr to set ipv6 address
971func (vs *VoltService) SetIpv6Addr(addr net.IP) {
972 vs.Ipv6Addr = addr
973}
974
975// SetMacAddr to set mac address
976func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
977 vs.MacAddr = addr
978}
979
980// ----------------------------------------------
981// VOLT Application - Related to services
982// ---------------------------------------------
983// ---------------------------------------------------------------
984// Service CRUD functions. These are exposed to the overall binary
985// to be invoked from the point where the CRUD operations are received
986// from the external entities
987
988// AddService : A service in the context of VOLT is a subscriber or service of a
989// subscriber which is uniquely identified by a combination of MAC
990// address, VLAN tags, 802.1p bits. However, in the context of the
991// current implementation, a service is an entity that is identified by a
992// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
993// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530994func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530995 var mmUs, mmDs *VoltMeter
996 var err error
997
998 //Take the Device lock only in case of NB add request.
999 // Allow internal adds since internal add happen only under
1000 // 1. Restore Service from DB
1001 // 2. Service Migration
1002 if oper == nil {
1003 if svc := va.GetService(cfg.Name); svc != nil {
1004 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
1005 return errors.New("Service Already Exists")
1006 }
1007 }
1008
1009 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
1010 // Service doesn't exist. So create it and add to the port
1011 vs := NewVoltService(&cfg)
1012 if oper != nil {
1013 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1014 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1015 vs.Ipv4Addr = oper.Ipv4Addr
1016 vs.Ipv6Addr = oper.Ipv6Addr
1017 vs.MacLearning = cfg.MacLearning
1018 vs.PendingFlows = oper.PendingFlows
1019 vs.AssociatedFlows = oper.AssociatedFlows
1020 vs.DeleteInProgress = oper.DeleteInProgress
1021 vs.BwAvailInfo = oper.BwAvailInfo
1022 vs.Device = oper.Device
1023 } else {
1024
1025 //Sorting Pbit from highest
1026 sort.Slice(vs.Pbits, func(i, j int) bool {
1027 return vs.Pbits[i] > vs.Pbits[j]
1028 })
1029 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1030 }
1031 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1032
1033 // The bandwidth and shaper profile combined into meter
1034 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1035 vs.DsMeterID = mmDs.ID
1036 } else {
1037 return errors.New("DownStream meter profile not found")
1038 }
1039
1040 // The aggregated downstream meter profile
1041 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1042 // vs.AggDsMeterID = mmAg.ID
1043 // } else {
1044 // return errors.New("Aggregated meter profile not found")
1045 // }
1046
1047 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1048 // vs.UsMeterID = mmAg.ID
1049 // } else {
1050 // The bandwidth and shaper profile combined into meter
1051 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1052 vs.UsMeterID = mmUs.ID
1053 } else {
1054 return errors.New("Upstream meter profile not found")
1055 }
1056 //}
1057
1058 AppMutex.ServiceDataMutex.Lock()
1059 defer AppMutex.ServiceDataMutex.Unlock()
1060
1061 // Add the service to the VNET
1062 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1063 if vnet != nil {
1064 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1065 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301066 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301067 vpv.VpvLock.Unlock()
1068 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301069 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301070 }
1071 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301072 logger.Errorw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301073 return errors.New("VNET doesn't exist")
1074 }
1075
1076 vs.Version = database.PresentVersionMap[database.ServicePath]
1077 // Add the service to the volt application
1078 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301079 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301080
1081 if nil == oper {
1082
1083 if !vs.UsHSIAFlowsApplied {
1084 vs.triggerServiceInProgressInd()
1085 }
1086
1087 //Update meter profiles service count if service is being added from northbound
1088 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301089 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301090 if mmUs != nil {
1091 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301092 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301093 }
1094 //mmAg.AssociatedServices++
1095 //va.UpdateMeterProf(*mmAg)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301096 logger.Debugw(ctx, "northbound-service-add-sucessful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301097 }
1098
1099 logger.Warnw(ctx, "Added Service to DB", log.Fields{"Name": vs.Name, "Port": (vs.Port), "ML": vs.MacLearning})
1100 return nil
1101}
1102
1103//DelServiceWithPrefix - Deletes service with the provided prefix.
1104// Added for DT/TT usecase with sadis replica interface
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301105func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301106 va.ServiceByName.Range(func(key, value interface{}) bool {
1107 srvName := key.(string)
1108 vs := value.(*VoltService)
1109 if strings.Contains(srvName, prefix) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301110 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301111
1112 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1113 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1114 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1115
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301116 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301117 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1118 }
1119 }
1120 return true
1121 })
1122}
1123
1124// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301125func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301126
1127 AppMutex.ServiceDataMutex.Lock()
1128 defer AppMutex.ServiceDataMutex.Unlock()
1129
1130 logger.Warnw(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
1131 var noFlowsPresent bool
1132
1133 vsIntf, ok := va.ServiceByName.Load(name)
1134 if !ok {
1135 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1136 return
1137 }
1138 vs := vsIntf.(*VoltService)
1139 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1140 if vpv == nil {
1141 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
1142 return
1143 }
1144
1145 //Set this to avoid race-condition during flow result processing
1146 vs.DeleteInProgress = true
1147 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301148 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301149
1150 if len(vs.AssociatedFlows) == 0 {
1151 noFlowsPresent = true
1152 }
1153 vpv.VpvLock.Lock()
1154 defer vpv.VpvLock.Unlock()
1155
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301156 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301157
1158 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301159 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301160 }
1161 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 +05301162 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301163 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301164 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301165 }
1166
1167 // Delete the service immediately in case of Force Delete
1168 // This will be enabled when profile reconciliation happens after restore
1169 // of backedup data
1170 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301171 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301172 GetApplication().ServiceByName.Delete(vs.Name)
1173 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1174 }
1175
1176 meterProfiles := make(map[*VoltMeter]bool)
1177
1178 if nil != newSvc {
1179 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1180 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1181 }
1182 skipMeterDeletion := false
1183 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1184 if nil != newSvc && aggMeter.Name == newSvc.AggDsMeterProfile {
1185 skipMeterDeletion = true
1186 }
1187
1188 meterProfiles[aggMeter] = skipMeterDeletion
1189 skipMeterDeletion = false
1190 }
1191 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
1192 if nil != newSvc && dsMeter.Name == newSvc.DsMeterProfile {
1193 skipMeterDeletion = true
1194 }
1195 meterProfiles[dsMeter] = skipMeterDeletion
1196 skipMeterDeletion = false
1197 }
1198 if vs.AggDsMeterID != vs.UsMeterID {
1199 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
1200 if nil != newSvc && usMeter.Name == newSvc.UsMeterProfile {
1201 skipMeterDeletion = true
1202 }
1203 meterProfiles[usMeter] = skipMeterDeletion
1204 }
1205 }
1206
1207 for meter, skipMeterDeletion := range meterProfiles {
1208 if nil == meter {
1209 logger.Debug(ctx, "Null meter found, continuing")
1210 continue
1211 }
1212 if meter.AssociatedServices > 0 {
1213 meter.AssociatedServices--
1214 if meter.AssociatedServices == 0 && !skipMeterDeletion {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301215 logger.Infow(ctx, "Meter should be deleted now\n", log.Fields{"MeterID": meter})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301216 va.UpdateMeterProf(cntx, *meter)
Naveen Sampath04696f72022-06-13 15:19:14 +05301217 }
1218 }
1219 }
1220
1221 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301222 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301223 }
1224
1225 //Delete the per service counter too
1226 va.ServiceCounters.Delete(name)
1227 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301228 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301229 }
1230}
1231
1232//AddFlows - Adds the flow to the service
1233// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301234func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301235
1236 // Using locks instead of concurrent map for PendingFlows to avoid
1237 // race condition during flow response indication processing
1238 vs.ServiceLock.Lock()
1239 defer vs.ServiceLock.Unlock()
1240
1241 for cookie := range flow.SubFlows {
1242 cookie := strconv.FormatUint(cookie, 10)
1243 fe := &FlowEvent{
1244 eType: EventTypeServiceFlowAdded,
1245 device: device.Name,
1246 cookie: cookie,
1247 eventData: vs,
1248 }
1249 device.RegisterFlowAddEvent(cookie, fe)
1250 vs.PendingFlows[cookie] = true
1251 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301252 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301253}
1254
1255//FlowInstallSuccess - Called when corresponding service flow installation is success
1256// If no more pending flows, HSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301257func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301258 if vs.DeleteInProgress {
1259 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1260 return
1261 }
1262 vs.ServiceLock.Lock()
1263
1264 if _, ok := vs.PendingFlows[cookie]; !ok {
1265 logger.Errorw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1266 vs.ServiceLock.Unlock()
1267 return
1268 }
1269
1270 delete(vs.PendingFlows, cookie)
1271 vs.AssociatedFlows[cookie] = true
1272 vs.ServiceLock.Unlock()
1273 var prevBwAvail, presentBwAvail string
1274 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1275 prevBwAvail = bwAvailInfo.PrevBw
1276 presentBwAvail = bwAvailInfo.PresentBw
1277 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301278 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301279 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301280 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301281
1282 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
1283
1284 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1285 if err != nil {
1286 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1287 return
1288 } else if device.State != controller.DeviceStateUP {
1289 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1290 return
1291 }
1292
1293 if vs.Trigger == ServiceVlanUpdate {
1294 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301295 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301296 }
1297 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1298 return
1299 }
1300 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1301}
1302
1303//FlowInstallFailure - Called when corresponding service flow installation is failed
1304// Trigger service failure indication to NB
1305func (vs *VoltService) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
1306 vs.ServiceLock.RLock()
1307
1308 if _, ok := vs.PendingFlows[cookie]; !ok {
1309 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1310 vs.ServiceLock.RUnlock()
1311 return
1312 }
1313 vs.ServiceLock.RUnlock()
1314 logger.Errorw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1315 vs.triggerServiceFailureInd(errorCode, errReason)
1316}
1317
1318//DelFlows - Deletes the flow from the service
1319// Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301320func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301321
1322 if !vs.ForceDelete {
1323 // Using locks instead of concurrent map for AssociatedFlows to avoid
1324 // race condition during flow response indication processing
1325 vs.ServiceLock.Lock()
1326 defer vs.ServiceLock.Unlock()
1327
1328 for cookie := range flow.SubFlows {
1329 cookie := strconv.FormatUint(cookie, 10)
1330 fe := &FlowEvent{
1331 eType: EventTypeServiceFlowRemoved,
1332 cookie: cookie,
1333 eventData: vs,
1334 }
1335 device.RegisterFlowDelEvent(cookie, fe)
1336 }
1337 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301338 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301339}
1340
1341//CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301342func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301343 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301344 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301345 GetApplication().ServiceByName.Delete(vs.Name)
1346 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1347 }
1348}
1349
1350//FlowRemoveSuccess - Called when corresponding service flow removal is success
1351// If no more associated flows, DelHSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301352func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301353
1354 // if vs.DeleteInProgress {
1355 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1356 // return
1357 // }
1358 vs.ServiceLock.Lock()
1359 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1360
1361 if _, ok := vs.AssociatedFlows[cookie]; ok {
1362 delete(vs.AssociatedFlows, cookie)
1363 } else if _, ok := vs.PendingFlows[cookie]; ok {
1364 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})
1365 } else {
1366 logger.Errorw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
1367 }
1368
1369 vs.ServiceLock.Unlock()
1370
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301371 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301372
1373 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
1374
1375 device := GetApplication().GetDevice(vs.Device)
1376 if device == nil {
1377 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1378 return
1379 } else if device.State != controller.DeviceStateUP {
1380 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1381 return
1382 }
1383
1384 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301385 vs.updateVnetProfile(cntx, vs.Device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301386 //Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
1387 return
1388 }
1389 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 +05301390 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301391
1392 return
1393 }
1394 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1395}
1396
1397//FlowRemoveFailure - Called when corresponding service flow installation is failed
1398// Trigger service failure indication to NB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301399func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301400 vs.ServiceLock.RLock()
1401
1402 if _, ok := vs.AssociatedFlows[cookie]; !ok {
1403 logger.Errorw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1404 vs.ServiceLock.RUnlock()
1405 return
1406 }
1407 if vs.DeleteInProgress {
1408 delete(vs.AssociatedFlows, cookie)
1409 }
1410 vs.ServiceLock.RUnlock()
1411 logger.Errorw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1412
1413 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301414 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301415}
1416
1417func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
1418 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1419 if err != nil {
1420 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1421 return
1422 } else if device.State != controller.DeviceStateUP {
1423 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1424 return
1425 }
1426}
1427
1428// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301429func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301430 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301431 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301432 for _, vs := range vss {
1433 b, ok := vs.Value.([]byte)
1434 if !ok {
1435 logger.Warn(ctx, "The value type is not []byte")
1436 continue
1437 }
1438 var vvs VoltService
1439 err := json.Unmarshal(b, &vvs)
1440 if err != nil {
1441 logger.Warn(ctx, "Unmarshal of VNET failed")
1442 continue
1443 }
1444 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301445 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301446 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1447 }
1448
1449 if vvs.VoltServiceOper.DeleteInProgress {
1450 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1451 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1452 }
1453 }
1454}
1455
1456// GetService to get service
1457func (va *VoltApplication) GetService(name string) *VoltService {
1458 if vs, ok := va.ServiceByName.Load(name); ok {
1459 return vs.(*VoltService)
1460 }
1461 return nil
1462}
1463
1464// GetCircuitID to get circuit id
1465func (vs *VoltService) GetCircuitID() []byte {
1466 return []byte(vs.CircuitID)
1467}
1468
1469// GetRemoteID to get remote id
1470func (vs *VoltService) GetRemoteID() []byte {
1471 return []byte(vs.RemoteID)
1472}
1473
1474// IPAssigned to check if ip is assigned
1475func (vs *VoltService) IPAssigned() bool {
1476 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1477 return true
1478 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1479 return true
1480 }
1481 return false
1482}
1483
1484// GetServiceNameFromCookie to get service name from cookie
1485func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
1486
1487 var vlan uint64
1488 vlanControl := (tableMetadata >> 32) & 0xF
1489
1490 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1491 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1492 vlan = (tableMetadata >> 16) & 0xFFFF
1493 } else {
1494 //Fetching CVlan for other vlanControl
1495 vlan = cookie >> 52
1496 }
1497 logger.Infow(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
1498 var vlans []of.VlanType
1499 vlans = append(vlans, of.VlanType(vlan))
1500 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1501 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301502 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301503 } else {
1504 logger.Errorw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
1505 }
1506 return service
1507}
1508
1509//MigrateServicesReqStatus - update vnet request status
1510type MigrateServicesReqStatus string
1511
1512const (
1513 //MigrateSrvsReqInit constant
1514 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
1515 //MigrateSrvsReqDeactTriggered constant
1516 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
1517 //MigrateSrvsReqCompleted constant
1518 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1519)
1520
1521//MigrateServicesRequest - update vnet request params
1522type MigrateServicesRequest struct {
1523 ID string
1524 OldVnetID string
1525 NewVnetID string
1526 ServicesList map[string]bool
1527 DeviceID string
1528 Status MigrateServicesReqStatus
1529 MigrateServicesLock sync.RWMutex
1530}
1531
1532func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
1533
1534 var msr MigrateServicesRequest
1535 msr.OldVnetID = oldVnetID
1536 msr.NewVnetID = newVnetID
1537 msr.ID = id
1538 msr.ServicesList = serviceMap
1539 msr.DeviceID = deviceID
1540 msr.Status = MigrateSrvsReqInit
1541 return &msr
1542}
1543
1544//GetMsrKey - generates migrate service request key
1545func (msr *MigrateServicesRequest) GetMsrKey() string {
1546 return msr.OldVnetID + "-" + msr.ID
1547}
1548
1549// //isRequestComplete - return if all request has been processed and completed
1550// // RequestProcessed indicates that all the profile de-activation has been triggered
1551// // And the associated profiles indicates the profiles awaiting results
1552// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1553// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1554// return (len(edr.AssociatedProfiles) == 0)
1555// }
1556
1557//WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301558func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301559 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)})
1560 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301561 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301562 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
1563 "Device": msr.DeviceID, "Error": err})
1564 }
1565 }
1566}
1567
1568//MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301569func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301570
1571 logger.Warnw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
1572 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
1573 return errors.New("Old Vnet Id not found")
1574 }
1575 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
1576 return errors.New("New Vnet Id not found")
1577 }
1578
1579 d := va.GetDeviceBySerialNo(serialNum)
1580 if d == nil {
1581 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1582 return errorCodes.ErrDeviceNotFound
1583 }
1584
1585 serviceMap := make(map[string]bool)
1586
1587 for _, service := range serviceList {
1588 serviceMap[service] = false
1589 }
1590 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301591 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301592
1593 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301594 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301595 return nil
1596}
1597
1598//ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301599func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301600 va := GetApplication()
1601 for srv, processed := range msr.ServicesList {
1602
1603 //Indicates new service is already created and only deletion of old one is pending
1604 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301605 va.DelService(cntx, srv, true, nil, true)
1606 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301607 continue
1608 }
1609
1610 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1611 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1612 vs := vsIntf.(*VoltService)
1613 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1614 if vpv == nil {
1615 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
1616 continue
1617 }
1618 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1619 vpv.Blocked = true
1620
1621 // setDeactTrigger := func(key, value interface{}) bool {
1622 // vs := value.(*VoltService)
1623 vs.ServiceLock.Lock()
1624 vs.UpdateInProgress = true
1625 metadata := &MigrateServiceMetadata{
1626 NewVnetID: msr.NewVnetID,
1627 RequestID: msr.ID,
1628 }
1629 vs.Metadata = metadata
1630 vs.ServiceLock.Unlock()
1631
1632 //vpv flows will be removed when last service is removed from it and
1633 // new vpv flows will be installed when new service is added
1634 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301635 vpv.DelTrapFlows(cntx)
1636 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301637 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301638 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301639 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301640 }
1641 } else {
1642 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1643 }
1644 }
1645}
1646
1647//AddMigratingServices - store msr info to device obj
1648func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
1649
1650 var msrMap *util.ConcurrentMap
1651 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1652 msrMap = util.NewConcurrentMap()
1653 } else {
1654 msrMap = msrMapIntf.(*util.ConcurrentMap)
1655 }
1656
1657 msrMap.Set(msr.ID, msr)
1658 logger.Infow(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
1659
1660 d.MigratingServices.Set(msr.OldVnetID, msrMap)
1661 logger.Infow(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
1662
1663}
1664
1665//getMigrateServicesRequest - fetches msr info from device
1666func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
1667 if vd := va.GetDevice(deviceID); vd != nil {
1668 logger.Infow(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
1669 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1670 msrList := msrListIntf.(*util.ConcurrentMap)
1671 logger.Infow(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
1672 if msrObj, ok := msrList.Get(requestID); ok {
1673 return msrObj.(*MigrateServicesRequest)
1674 }
1675
1676 }
1677 }
1678 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
1679 return nil
1680}
1681
1682//updateMigrateServicesRequest - Updates the device with updated msr
1683func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
1684 if vd := va.GetDevice(deviceID); vd != nil {
1685 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1686 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1687 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1688 }
1689 }
1690 }
1691}
1692
1693//updateVnetProfile - Called on flow process completion
1694// Removes old service and creates new VPV & service with udpated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301695func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301696
Tinoj Joseph1d108322022-07-13 10:07:39 +05301697 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 +05301698
1699 nvs := VoltService{}
1700 nvs.VoltServiceCfg = vs.VoltServiceCfg
1701 nvs.Device = vs.Device
1702 nvs.Ipv4Addr = vs.Ipv4Addr
1703 nvs.Ipv6Addr = vs.Ipv6Addr
1704 nvs.UsMeterID = vs.UsMeterID
1705 nvs.DsMeterID = vs.DsMeterID
1706 nvs.AggDsMeterID = vs.AggDsMeterID
1707 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1708 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1709 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1710 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1711 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1712 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1713 nvs.PendingFlows = vs.PendingFlows
1714 nvs.AssociatedFlows = vs.AssociatedFlows
1715 nvs.DeleteInProgress = vs.DeleteInProgress
1716 nvs.ForceDelete = vs.ForceDelete
1717 nvs.BwAvailInfo = vs.BwAvailInfo
1718 nvs.UpdateInProgress = vs.UpdateInProgress
1719
1720 if nvs.DeleteInProgress {
1721 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1722 return
1723 }
1724
1725 metadata := vs.Metadata.(*MigrateServiceMetadata)
1726 oldVnetID := vs.VnetID
1727 nvs.VnetID = metadata.NewVnetID
1728 id := metadata.RequestID
1729 oldSrvName := vs.Name
1730
1731 if metadata == nil || metadata.NewVnetID == "" {
1732 logger.Errorw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
1733 return
1734 }
1735
1736 //First add the new service and then only delete the old service
1737 // Since if post del service in case of pod crash or reboot, the service data will be lost
1738 va := GetApplication()
1739 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1740 vnets := strings.Split(metadata.NewVnetID, "-")
1741 svlan, _ := strconv.Atoi(vnets[0])
1742 nvs.SVlan = of.VlanType(svlan)
1743 nvs.UpdateInProgress = false
1744 nvs.Metadata = nil
1745 nvs.Trigger = ServiceVlanUpdate
1746
1747 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1748 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1749 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1750
1751 //TODO:Nav Pass a copy, not the pointer
1752 logger.Infow(ctx, "Add New Service Triggering", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301753 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301754 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1755 }
1756 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1757
1758 msr.ServicesList[oldSrvName] = true
1759 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301760 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301761
1762 logger.Infow(ctx, "Del Old Service Triggering", log.Fields{"Service": oldSrvName, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied, "DelFlag": vs.DeleteInProgress})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301763 va.DelService(cntx, oldSrvName, true, nil, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301764 logger.Infow(ctx, "Del Old Service Triggered", log.Fields{"Service": oldSrvName, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied, "DelFlag": vs.DeleteInProgress})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301765 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301766}
1767
1768//serviceMigrated - called on successful service updation
1769// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301770func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301771
1772 msr.MigrateServicesLock.Lock()
1773 defer msr.MigrateServicesLock.Unlock()
1774
1775 delete(msr.ServicesList, serviceName)
1776
1777 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301778 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301779 return
1780 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301781 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301782 //TODO:Nav - Need for any Response to SubMgr?
1783}
1784
1785//TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301786func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1787 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301788}
1789
1790//FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301791func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301792
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301793 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301794 for _, msr := range msrList {
1795 b, ok := msr.Value.([]byte)
1796 if !ok {
1797 logger.Warn(ctx, "The value type is not []byte")
1798 continue
1799 }
1800 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301801 msrAction(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301802 logger.Warnw(ctx, "Triggering Pending Migrate Services Req", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID, "Device": device, "PendingProfiles": len(msr.ServicesList)})
1803
1804 }
1805}
1806
1807// createMigrateServicesFromString to create Service from string
1808func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
1809 var msr MigrateServicesRequest
1810 if err := json.Unmarshal(b, &msr); err == nil {
1811 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
1812
1813 } else {
1814 logger.Warn(ctx, "Unmarshal failed")
1815 }
1816 return &msr
1817}
1818
1819//storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301820func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301821 d := GetApplication().GetDevice(msr.DeviceID)
1822 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301823 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301824}
1825
1826//forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301827func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301828 for srv := range msr.ServicesList {
1829 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301830 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301831 }
1832 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301833 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301834}
1835
1836//DeepEqualServicecfg - checks if the given service cfgs are same
1837func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1838 if nvs.Name != evs.Name {
1839 return false
1840 }
1841 if nvs.UniVlan != evs.UniVlan {
1842 return false
1843 }
1844 if nvs.CVlan != evs.CVlan {
1845 return false
1846 }
1847 if nvs.SVlan != evs.SVlan {
1848 return false
1849 }
1850 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1851 return false
1852 }
1853 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1854 return false
1855 }
1856 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1857 return false
1858 }
1859 if nvs.TechProfileID != evs.TechProfileID {
1860 return false
1861 }
1862 if nvs.CircuitID != evs.CircuitID {
1863 return false
1864 }
1865 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1866 return false
1867 }
1868 if nvs.Port != evs.Port {
1869 return false
1870 }
1871 if nvs.PonPort != evs.PonPort {
1872 return false
1873 }
1874 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1875 return false
1876 }
1877 if nvs.IsOption82Disabled != evs.IsOption82Disabled {
1878 return false
1879 }
1880 if nvs.IgmpEnabled != evs.IgmpEnabled {
1881 return false
1882 }
1883 if nvs.McastService != evs.McastService {
1884 return false
1885 }
1886 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1887 return false
1888 }
1889 if nvs.UsMeterProfile != evs.UsMeterProfile {
1890 return false
1891 }
1892 if nvs.DsMeterProfile != evs.DsMeterProfile {
1893 return false
1894 }
1895 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
1896 return false
1897 }
1898 if nvs.VnetID != evs.VnetID {
1899 return false
1900 }
1901 if nvs.MvlanProfileName != evs.MvlanProfileName {
1902 return false
1903 }
1904 if nvs.RemoteIDType != evs.RemoteIDType {
1905 return false
1906 }
1907 if nvs.SchedID != evs.SchedID {
1908 return false
1909 }
1910 if nvs.AllowTransparent != evs.AllowTransparent {
1911 return false
1912 }
1913 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
1914 return false
1915 }
1916 if nvs.DataRateAttr != evs.DataRateAttr {
1917 return false
1918 }
1919 if nvs.MinDataRateUs != evs.MinDataRateUs {
1920 return false
1921 }
1922 if nvs.MinDataRateDs != evs.MinDataRateDs {
1923 return false
1924 }
1925 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
1926 return false
1927 }
1928 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
1929 return false
1930 }
1931
1932 return true
1933}
1934
1935//TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301936func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301937
1938 //Clear the Flows flag if already set
1939 //This case happens only in case of some race condition
1940 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301941 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301942 logger.Errorw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1943 }
1944 }
1945
1946 if vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301947 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301948 logger.Errorw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1949 }
1950 }
1951
1952 vs.ServiceLock.Lock()
1953 cookieList := []uint64{}
1954 for cookie := range vs.AssociatedFlows {
1955 cookieList = append(cookieList, convertToUInt64(cookie))
1956 }
1957 vs.ServiceLock.Unlock()
1958
1959 if len(cookieList) == 0 {
1960 return false
1961 }
1962
1963 //Trigger Flow Delete
1964 for _, cookie := range cookieList {
1965 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
1966 flow := &of.VoltFlow{}
1967 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1968 subFlow := of.NewVoltSubFlow()
1969 subFlow.Cookie = cookie
1970 flow.SubFlows[cookie] = subFlow
1971 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301972 if err := vs.DelFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301973 logger.Errorw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
1974 }
1975 }
1976 }
1977 return true
1978}
1979
1980//triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
1981func (vs *VoltService) triggerServiceInProgressInd() {
1982}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301983
1984// JsonMarshal wrapper function for json Marshal VoltService
1985func (vs *VoltService) JsonMarshal() ([]byte, error) {
1986 return json.Marshal(VoltService{
1987 VoltServiceCfg: vs.VoltServiceCfg,
1988 VoltServiceOper: VoltServiceOper{
1989 Device: vs.VoltServiceOper.Device,
1990 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
1991 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
1992 UsMeterID: vs.VoltServiceOper.UsMeterID,
1993 DsMeterID: vs.VoltServiceOper.DsMeterID,
1994 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
1995 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
1996 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
1997 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
1998 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
1999 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
2000 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
2001 PendingFlows: vs.VoltServiceOper.PendingFlows,
2002 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
2003 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2004 ForceDelete: vs.VoltServiceOper.ForceDelete,
2005 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2006 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2007 Metadata: vs.VoltServiceOper.Metadata,
2008 },
2009 })
2010}
Tinoj Josephec742f62022-09-29 19:11:10 +05302011
2012// GetProgrammedSubscribers to get list of programmed subscribers
2013func (va *VoltApplication) GetProgrammedSubscribers (cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
2014 var svcList []*VoltService
2015 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2016 va.ServiceByName.Range(func(key, value interface{}) bool {
2017 vs := value.(*VoltService)
2018 if (len(deviceID) > 0 ) {
2019 if (len(portNo) > 0) {
2020 if deviceID == vs.Device && portNo == vs.Port {
2021 svcList = append(svcList, vs)
2022 }
2023 } else {
2024 if deviceID == vs.Device {
2025 svcList = append(svcList, vs)
2026 }
2027 }
2028 } else {
2029 svcList = append(svcList, vs)
2030 }
2031 return true
2032 })
2033 return svcList, nil
2034}
2035
2036// ActivateService to activate pre-provisioned service
2037func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) {
2038 logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2039 va.ServiceByName.Range(func(key, value interface{}) bool {
2040 vs := value.(*VoltService)
2041 // If device id is not provided check only port number
2042 if deviceID == DeviceAny {
2043 deviceID = vs.Device
2044 }
2045 // If svlan if provided, then the tags and tpID of service has to be matching
2046 if (sVlan != of.VlanNone && ( sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) ) {
2047 return true
2048 }
2049 if portNo == vs.Port && !vs.IsActivated {
2050 d := va.GetDevice(deviceID)
2051 if d == nil {
2052 logger.Warnw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
2053 return true
2054 }
2055 p := d.GetPort(vs.Port)
2056 if p == nil {
2057 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2058 return true
2059 }
2060 logger.Infow(ctx, "Service Activate", log.Fields{"Name": vs.Name})
2061 vs.IsActivated = true
2062 va.ServiceByName.Store(vs.Name, vs)
2063 vs.WriteToDb(cntx)
2064 // If port is already up send indication to vpv
2065 if p.State == PortStateUp {
2066 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2067 // PortUp call initiates flow addition
2068 vpv.PortUpInd(cntx, d, portNo)
2069 } else {
2070 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2071 }
2072 }
2073 }
2074 return true
2075 })
2076}
2077
2078// DeactivateService to activate pre-provisioned service
2079func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) {
2080 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2081 va.ServiceByName.Range(func(key, value interface{}) bool {
2082 vs := value.(*VoltService)
2083 // If svlan if provided, then the tags and tpID of service has to be matching
2084 if (sVlan != of.VlanNone && ( sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) ) {
2085 return true
2086 }
2087 // If device id is not provided check only port number
2088 if deviceID == DeviceAny {
2089 deviceID = vs.Device
2090 }
2091 if deviceID == vs.Device && portNo == vs.Port && vs.IsActivated {
2092 vs.IsActivated = false
2093 va.ServiceByName.Store(vs.Name, vs)
2094 vs.WriteToDb(cntx)
2095 d := va.GetDevice(deviceID)
2096 if d == nil {
2097 logger.Warnw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
2098 return true
2099 }
2100 p := d.GetPort(vs.Port)
2101 if p != nil && p.State == PortStateUp {
2102 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2103 // Port down call internally deletes all the flows
2104 vpv.PortDownInd(cntx, deviceID, portNo)
2105 if vpv.IgmpEnabled {
2106 va.ReceiverDownInd(cntx, deviceID, portNo)
2107 }
2108 } else {
2109 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2110 }
2111 }
2112 }
2113 return true
2114 })
2115}
2116
2117/* GetServicePbit to get first set bit in the pbit map
2118 returns -1 : If configured to match on all pbits
2119 returns 8 : If no pbits are configured
2120 returns first pbit if specific pbit is configured */
2121func (vs *VoltService) GetServicePbit() int {
2122 if vs.IsPbitExist(of.PbitMatchAll) {
2123 return -1
2124 }
2125 for pbit:= 0; pbit < int(of.PbitMatchNone); pbit++ {
2126 if vs.IsPbitExist(of.PbitType(pbit)) {
2127 return pbit
2128 }
2129 }
2130 return int(of.PbitMatchNone)
2131}