blob: 9315b5be9755db8da67961acad51ec75fe66c7b8 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053014 */
Naveen Sampath04696f72022-06-13 15:19:14 +053015
16package application
17
18import (
19 "bytes"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053020 "context"
Naveen Sampath04696f72022-06-13 15:19:14 +053021 "encoding/json"
22 "errors"
23 "net"
24 "reflect"
Naveen Sampath04696f72022-06-13 15:19:14 +053025 "sort"
26 "strconv"
27 "strings"
28 "sync"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053029 infraerrorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053030
31 "github.com/google/gopacket/layers"
32
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053033 "voltha-go-controller/database"
Naveen Sampath04696f72022-06-13 15:19:14 +053034 "voltha-go-controller/internal/pkg/controller"
35 cntlr "voltha-go-controller/internal/pkg/controller"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053036 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053037 "voltha-go-controller/internal/pkg/of"
38 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053039 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053040)
41
42const (
43 // DSLAttrEnabled constant
44 DSLAttrEnabled string = "ENABLED"
Tinoj Josephec742f62022-09-29 19:11:10 +053045 // DeviceAny constant
46 DeviceAny string = "DEVICE-ANY"
Naveen Sampath04696f72022-06-13 15:19:14 +053047)
48
49// VoltServiceCfg structure
50// Name - Uniquely identifies a service across the entire application
51// UniVlan - The VLAN of the packets entering the UNI of ONU
52// CVlan - The VLAN to transalate to/from on the PON link
53// SVlan - The outer VLAN to be used on the NNI of OLT.
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
Tinoj Joseph50d722c2022-12-06 22:53:22 +053074 UsPonCTagPriority of.PbitType
75 UsPonSTagPriority of.PbitType
76 DsPonCTagPriority of.PbitType
77 DsPonSTagPriority of.PbitType
Naveen Sampath04696f72022-06-13 15:19:14 +053078 DsRemarkPbitsMap map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
79 TechProfileID uint16
80 CircuitID string
81 RemoteID []byte
82 Port string
83 PonPort uint32
84 MacLearning MacLearningType
85 IsOption82Disabled bool
86 IgmpEnabled bool
87 McastService bool
88 ONTEtherTypeClassification int
89 VlanControl VlanControl
90 UsMeterProfile string
91 DsMeterProfile string
92 AggDsMeterProfile string
93 VnetID string
94 MvlanProfileName string
95 RemoteIDType string
96 SchedID int
97 AllowTransparent bool
98 EnableMulticastKPI bool
99 DataRateAttr string
100 MinDataRateUs uint32
101 MinDataRateDs uint32
102 MaxDataRateUs uint32
103 MaxDataRateDs uint32
Tinoj Josephec742f62022-09-29 19:11:10 +0530104 IsActivated bool
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +0530105 Trigger ServiceTrigger
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530106 ServiceType string
Naveen Sampath04696f72022-06-13 15:19:14 +0530107}
108
109// VoltServiceOper structure
110type VoltServiceOper struct {
111 //MacLearning bool
112 //MacAddr net.HardwareAddr
113 Device string
114 Ipv4Addr net.IP
115 Ipv6Addr net.IP
116
117 UsMeterID uint32
118 DsMeterID uint32
119 AggDsMeterID uint32
120
121 //Multiservice-Fix
122 UsHSIAFlowsApplied bool
123 DsHSIAFlowsApplied bool
124 UsDhcpFlowsApplied bool
125 DsDhcpFlowsApplied bool
126 IgmpFlowsApplied bool
127 Icmpv6FlowsApplied bool
128
129 ServiceLock sync.RWMutex `json:"-"`
130 PendingFlows map[string]bool
131 AssociatedFlows map[string]bool
132 DeleteInProgress bool
133 ForceDelete bool
134 BwAvailInfo string
135
136 UpdateInProgress bool
137 Metadata interface{}
138}
139
140// VoltService structure
141type VoltService struct {
142 VoltServiceCfg
143 VoltServiceOper
144 Version string
145}
146
147//ServiceTrigger - Service activation trigger
148type ServiceTrigger int
149
150const (
151 //NBActivate - Service added due to NB Action
152 NBActivate ServiceTrigger = 0
153 //ServiceVlanUpdate - Service added due to Svlan Update
154 ServiceVlanUpdate ServiceTrigger = 1
155)
156
157// AppMutexes structure
158type AppMutexes struct {
159 ServiceDataMutex sync.Mutex `json:"-"`
160 VnetMutex sync.Mutex `json:"-"`
161}
162
163//MigrateServiceMetadata - migrate services request metadata
164type MigrateServiceMetadata struct {
165 NewVnetID string
166 RequestID string
167}
168
169// AppMutex variable
170var AppMutex AppMutexes
171
172// NewVoltService for constructor for volt service
173func NewVoltService(cfg *VoltServiceCfg) *VoltService {
174 var vs VoltService
175 vs.VoltServiceCfg = *cfg
176 vs.UsHSIAFlowsApplied = false
177 vs.DsHSIAFlowsApplied = false
178 vs.DeleteInProgress = false
179 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
180
181 vs.MacAddr = cfg.MacAddr
182 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
183 vs.Ipv6Addr = net.ParseIP("::")
184 vs.PendingFlows = make(map[string]bool)
185 vs.AssociatedFlows = make(map[string]bool)
186 return &vs
187}
188
189// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530190func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530191
192 vs.ServiceLock.RLock()
193 defer vs.ServiceLock.RUnlock()
194
195 if vs.DeleteInProgress {
196 logger.Warnw(ctx, "Skipping Redis Update for Service, Service delete in progress", log.Fields{"Service": vs.Name})
197 return
198 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530199 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530200}
201
202//ForceWriteToDb force commit a service to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530203func (vs *VoltService) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530204 b, err := json.Marshal(vs)
205
206 if err != nil {
207 logger.Errorw(ctx, "Json Marshal Failed for Service", log.Fields{"Service": vs.Name})
208 return
209 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530210 if err1 := db.PutService(cntx, vs.Name, string(b)); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530211 logger.Errorw(ctx, "DB write oper failed for Service", log.Fields{"Service": vs.Name})
212 }
213}
214
215// isDataRateAttrPresent to check if data attribute is present
216func (vs *VoltService) isDataRateAttrPresent() bool {
217 return vs.DataRateAttr == DSLAttrEnabled
218}
219
220// DelFromDb delete a service from DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530221func (vs *VoltService) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530222 logger.Debugw(ctx, "Deleting Service from DB", log.Fields{"Name": vs.Name})
223 //TODO - Need to understand and delete the second call
224 //Calling twice has worked though don't know why
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530225 _ = db.DelService(cntx, vs.Name)
226 _ = db.DelService(cntx, vs.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530227}
228
229// MatchesVlans find the service that matches the VLANs. In this case it is
230// purely based on CVLAN. The CVLAN can sufficiently be used to
231// match a service
232func (vs *VoltService) MatchesVlans(vlans []of.VlanType) bool {
233 if len(vlans) != 1 {
234 return false
235 }
236
237 if vlans[0] == vs.CVlan {
238 return true
239 }
240 return false
241}
242
243// MatchesPbits allows matching a service to a pbit. This is used
244// to search for a service matching the pbits, typically to identify
245// attributes for other flows such as DHCP, IGMP, etc.
246func (vs *VoltService) MatchesPbits(pbits []of.PbitType) bool {
247 for _, pbit := range pbits {
248 for _, pb := range vs.Pbits {
249 if pb == pbit {
250 return true
251 }
252 }
253 }
254 return false
255}
256
257// IsPbitExist allows matching a service to a pbit. This is used
258// to search for a service matching the pbit
259func (vs *VoltService) IsPbitExist(pbit of.PbitType) bool {
260 for _, pb := range vs.Pbits {
261 if pb == pbit {
262 return true
263 }
264 }
265 return false
266}
267
268// AddHsiaFlows - Adds US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530269func (vs *VoltService) AddHsiaFlows(cntx context.Context) {
270 if err := vs.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530271 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
272 vs.triggerServiceFailureInd(statusCode, statusMessage)
273 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530274 if err := vs.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530275 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
276 vs.triggerServiceFailureInd(statusCode, statusMessage)
277 }
278}
279
280//DelHsiaFlows - Deletes US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530281func (vs *VoltService) DelHsiaFlows(cntx context.Context) {
282 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530283 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
284 vs.triggerServiceFailureInd(statusCode, statusMessage)
285 }
286
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530287 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530288 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
289 vs.triggerServiceFailureInd(statusCode, statusMessage)
290 }
291}
292
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530293func (vs *VoltService) AddMeterToDevice(cntx context.Context) error {
294 if vs.DeleteInProgress || vs.UpdateInProgress {
295 logger.Errorw(ctx, "Ignoring Meter Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
296 }
297 va := GetApplication()
298 logger.Infow(ctx, "Configuring Meters for FTTB", log.Fields{"ServiceName": vs.Name})
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 Meter Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
305 return nil
306 }
307 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
308 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
309 return nil
310}
311
Naveen Sampath04696f72022-06-13 15:19:14 +0530312// AddUsHsiaFlows - Add US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530313func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530314
315 if vs.DeleteInProgress || vs.UpdateInProgress {
316 logger.Errorw(ctx, "Ignoring US HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
317 return nil
318 }
319
320 va := GetApplication()
321 logger.Infow(ctx, "Configuring US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
322 if !vs.UsHSIAFlowsApplied || vgcRebooted {
323 device, err := va.GetDeviceFromPort(vs.Port)
324 if err != nil {
325 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
326 return errorCodes.ErrDeviceNotFound
327 } else if device.State != controller.DeviceStateUP {
328 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
329 return nil
330 }
331
332 vs.Device = device.Name
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530333 /* In case of DPU_MGMT_TRAFFIC the meters will be configured before US flow creation*/
334 if vs.ServiceType != DPU_MGMT_TRAFFIC {
335 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
336 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
337 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530338 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
339 pBits := vs.Pbits
340
341 //If no pbits configured for service, hence add PbitNone for flows
342 if len(vs.Pbits) == 0 {
343 pBits = append(pBits, PbitMatchNone)
344 }
345 for _, pbits := range pBits {
346 usflows, err := vs.BuildUsHsiaFlows(pbits)
347 if err != nil {
348 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
349 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
350 vs.triggerServiceFailureInd(statusCode, statusMessage)
351 continue
352 }
353 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530354 if err := vs.AddFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530355 logger.Errorw(ctx, "Error adding HSIA US flows", log.Fields{"Reason": err.Error()})
356 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
357 vs.triggerServiceFailureInd(statusCode, statusMessage)
358 }
359 }
360 vs.UsHSIAFlowsApplied = true
361 logger.Infow(ctx, "Pushed US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
362 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530363 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530364 return nil
365}
366
367// AddDsHsiaFlows - Add DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530368func (vs *VoltService) AddDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530369 if vs.DeleteInProgress {
370 logger.Errorw(ctx, "Ignoring DS HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
371 return nil
372 }
373
374 va := GetApplication()
375 logger.Infow(ctx, "Configuring DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
376 if !vs.DsHSIAFlowsApplied || vgcRebooted {
377 device, err := va.GetDeviceFromPort(vs.Port)
378 if err != nil {
379 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
380 return errorCodes.ErrDeviceNotFound
381 } else if device.State != controller.DeviceStateUP {
382 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
383 return nil
384 }
385
386 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
387 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
388
389 //If no pbits configured for service, hence add PbitNone for flows
390 if len(vs.DsRemarkPbitsMap) == 0 {
391 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
392 if err != nil {
393 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
394 return err
395 }
396 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530397 if err = vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530398 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
399 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
400 vs.triggerServiceFailureInd(statusCode, statusMessage)
401 }
402 } else {
403 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
404 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
405 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
406 if err != nil {
407 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
408 return err
409 }
410 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
411 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530412 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530413 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
414 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
415 vs.triggerServiceFailureInd(statusCode, statusMessage)
416 }
417 } else {
418 for matchPbit := range vs.DsRemarkPbitsMap {
419 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
420 if err != nil {
421 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
422 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
423 vs.triggerServiceFailureInd(statusCode, statusMessage)
424 continue
425 }
426 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530427 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530428 logger.Errorw(ctx, "Failed to Add HSIA DS flows", log.Fields{"Reason": err})
429 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
430 vs.triggerServiceFailureInd(statusCode, statusMessage)
431 }
432 }
433 }
434 }
435 vs.DsHSIAFlowsApplied = true
436 logger.Infow(ctx, "Pushed DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
437 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530438 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530439 return nil
440}
441
442// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530443func (vs *VoltService) DelUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530444
445 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Services": vs.Name})
446 if vs.UsHSIAFlowsApplied || vgcRebooted {
447 device, err := GetApplication().GetDeviceFromPort(vs.Port)
448 if err != nil {
449 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
450 return errorCodes.ErrDeviceNotFound
451 }
452
453 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
454 pBits := vs.Pbits
455
456 //If no pbits configured for service, hence add PbitNone for flows
457 if len(vs.Pbits) == 0 {
458 pBits = append(pBits, PbitMatchNone)
459 }
460 for _, pbits := range pBits {
461 usflows, err := vs.BuildUsHsiaFlows(pbits)
462 if err != nil {
463 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
464 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
465 vs.triggerServiceFailureInd(statusCode, statusMessage)
466 continue
467 }
468 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530469 if err = vs.DelFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530470 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
471 vs.triggerServiceFailureInd(statusCode, statusMessage)
472 }
473 }
474 vs.UsHSIAFlowsApplied = false
475 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530476 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530477 return nil
478}
479
480// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530481func (vs *VoltService) DelDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530482
483 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Services": vs.Name})
484 if vs.DsHSIAFlowsApplied || vgcRebooted {
485 device, err := GetApplication().GetDeviceFromPort(vs.Port)
486 if err != nil {
487 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
488 return errorCodes.ErrDeviceNotFound
489 }
490
491 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
492 var matchPbit int
493 //If no pbits configured for service, hence add PbitNone for flows
494 if len(vs.DsRemarkPbitsMap) == 0 {
495 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
496 if err != nil {
497 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
498 return err
499 }
500 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530501 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530502 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
503 vs.triggerServiceFailureInd(statusCode, statusMessage)
504 }
505 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
506 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
507 if err != nil {
508 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
509 return err
510 }
511 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530512 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530513 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
514 vs.triggerServiceFailureInd(statusCode, statusMessage)
515 }
516 } else {
517 for matchPbit = range vs.DsRemarkPbitsMap {
518 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
519 if err != nil {
520 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
521 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
522 vs.triggerServiceFailureInd(statusCode, statusMessage)
523 continue
524 }
525 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530526 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530527 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
528 vs.triggerServiceFailureInd(statusCode, statusMessage)
529 }
530 }
531 }
532 vs.DsHSIAFlowsApplied = false
533 }
534 logger.Infow(ctx, "Deleted HSIA DS flows from DB successfuly", log.Fields{"ServiceName": vs.Name})
535 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530536 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530537 return nil
538}
539
540// BuildDsHsiaFlows build the DS HSIA flows
541// Called for add/delete HSIA flows
542func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
543 flow := &of.VoltFlow{}
544 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
545
546 // Get the out and in ports for the flows
547 device, err := GetApplication().GetDeviceFromPort(vs.Port)
548 if err != nil {
549 return nil, errorCodes.ErrDeviceNotFound
550 }
551 inport, _ := GetApplication().GetPortID(device.NniPort)
552 outport, _ := GetApplication().GetPortID(vs.Port)
553 // PortName and PortID to be used for validation of port before flow pushing
554 flow.PortID = outport
555 flow.PortName = vs.Port
556 allowTransparent := 0
557 if vs.AllowTransparent {
558 allowTransparent = 1
559 }
560
561 // initialized actnPbit to 0 for cookie genration backward compatibility.
562 var actnPbit of.PbitType
563 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
564
565 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
566 //| 12-bit cvlan/UniVlan | 4 bits action pbit | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
567 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
568 cookie = cookie | of.DsFlowMask
569 cookie = cookie + (valToShift << 4) + uint64(pbits)
570 return cookie
571 }
572
573 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
574 if err != nil {
575 logger.Errorw(ctx, "DS HSIA flow push failed: Invalid SvlanTpid", log.Fields{"SvlanTpid": vs.SVlanTpid, "Service": vs.Name})
576 return nil, err
577 }
578
579 // Add Table-0 flow that deals with the outer VLAN in pOLT
580 {
581 subflow1 := of.NewVoltSubFlow()
582 subflow1.SetTableID(0)
583 subflow1.SetGoToTable(1)
584 subflow1.SetInPort(inport)
585
586 if pbits != PbitMatchNone {
587 subflow1.SetMatchPbit(pbits)
588 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530589 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
590 subflow1.SetPcp(of.PbitType(remarkPbit))
591 // match & action pbits are different, set remark-pbit action
592 actnPbit = of.PbitType(remarkPbit)
593 // mask remark p-bit to 4bits
594 actnPbit = actnPbit & 0x0F
595 }
596
597 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
598 return nil, err
599 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530600 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530601 if NonZeroMacAddress(vs.MacAddr) {
602 subflow1.SetMatchDstMac(vs.MacAddr)
603 }
604 subflow1.Priority = of.HsiaFlowPriority
605 subflow1.SetMeterID(vs.DsMeterID)
606
607 /* WriteMetaData 8 Byte(uint64) usage:
608 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
609 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
610 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
611 subflow1.SetWriteMetadata(metadata)
612
613 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
614 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
615 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
616 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
617
618 //TODO-COMM:
619 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
620 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
621 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
622 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
623
624 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
625 subflow1.SetTableMetadata(metadata)
626 // TODO - We are using cookie as key and must come up with better cookie
627 // allocation algorithm
628 /**
629 * Cokies may clash when -
630 * on same uni-port we have two sub-service
631 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
632 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
633 * However, this p-bit re-use will not be allowed by sub-mgr.
634 */
635 if vs.VlanControl == OLTCVlanOLTSVlan {
636 /**
637 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
638 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
639 * use old cookie.
640 */
641 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
642 if vgcRebooted {
643 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
644 }
645 } else {
646 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
647 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
648 }
649
650 flow.SubFlows[subflow1.Cookie] = subflow1
651 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
652 "subflow": subflow1})
653 }
654
655 //Add Table-1 flow that deals with inner VLAN at the ONU
656 {
657 subflow2 := of.NewVoltSubFlow()
658 subflow2.SetTableID(1)
659 subflow2.SetInPort(inport)
660 if NonZeroMacAddress(vs.MacAddr) {
661 subflow2.SetMatchDstMac(vs.MacAddr)
662 }
663
664 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
665 return nil, err
666 }
667 if pbits != PbitMatchNone {
668 subflow2.SetMatchPbit(pbits)
669 }
670
671 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
672 subflow2.SetPcp(of.PbitType(remarkPbit))
673 }
674
675 subflow2.SetOutPort(outport)
676 subflow2.SetMeterID(vs.DsMeterID)
677
678 // refer Table-0 flow generation for byte information
679 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
680 subflow2.SetWriteMetadata(metadata)
681
682 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
683 if util.IsNniPort(inport) {
684 metadata = uint64(outport)
685 } else {
686 // refer Table-0 flow generation for byte information
687 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
688 }
689 subflow2.SetTableMetadata(metadata)
690 // Setting of Cookie - TODO - Improve the allocation algorithm
691 if vs.VlanControl == OLTCVlanOLTSVlan {
692 /**
693 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
694 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
695 * use old cookie.
696 */
697 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
698 if vgcRebooted {
699 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
700 }
701 } else {
702 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
703 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
704 }
705
706 subflow2.Priority = of.HsiaFlowPriority
707 flow.SubFlows[subflow2.Cookie] = subflow2
708 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
709 "subflow": subflow2})
710 }
711
712 return flow, nil
713}
714
715// BuildUsHsiaFlows build the US HSIA flows
716// Called for add/delete HSIA flows
717func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
718 flow := &of.VoltFlow{}
719 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
720
721 // Get the out and in ports for the flows
722 device, err := GetApplication().GetDeviceFromPort(vs.Port)
723 if err != nil {
724 return nil, errorCodes.ErrDeviceNotFound
725 }
726 outport, _ := GetApplication().GetPortID(device.NniPort)
727 inport, _ := GetApplication().GetPortID(vs.Port)
728 // PortName and PortID to be used for validation of port before flow pushing
729 flow.PortID = inport
730 flow.PortName = vs.Port
Naveen Sampath04696f72022-06-13 15:19:14 +0530731
732 // Add Table-0 flow that deals with the inner VLAN in ONU
733 {
734 subflow1 := of.NewVoltSubFlow()
735 subflow1.SetTableID(0)
736 subflow1.SetGoToTable(1)
737 subflow1.SetInPort(inport)
738
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530739 if vs.ServiceType == DPU_MGMT_TRAFFIC {
740 subflow1.SetMatchPbit(vs.UsPonCTagPriority)
741 subflow1.SetPcp(vs.UsPonSTagPriority)
742 } else if vs.ServiceType == DPU_ANCP_TRAFFIC {
743 subflow1.SetPcp(vs.UsPonSTagPriority)
744 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530745 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
746 return nil, err
747 }
748 subflow1.SetMeterID(vs.UsMeterID)
749
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530750 /* WriteMetaData 8 Byte(uint64) usage:
751 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
752 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
753 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
754 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
755 subflow1.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530756
Naveen Sampath04696f72022-06-13 15:19:14 +0530757 if vs.VlanControl == OLTCVlanOLTSVlan {
758 /**
759 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
760 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
761 * use old cookie.
762 */
763 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
764 if vgcRebooted {
765 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
766 }
767 } else {
768 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
769 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
770 }
771 subflow1.Priority = of.HsiaFlowPriority
772 flow.SubFlows[subflow1.Cookie] = subflow1
773 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
774 }
775
776 //Add Table-1 flow that deals with the outer vlan in pOLT
777 {
778 subflow2 := of.NewVoltSubFlow()
779 subflow2.SetTableID(1)
780 subflow2.SetInPort(inport)
781
Naveen Sampath04696f72022-06-13 15:19:14 +0530782 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
783 return nil, err
784 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530785 if vs.ServiceType == DPU_MGMT_TRAFFIC {
786 subflow2.SetMatchSrcMac(vs.MacAddr)
787 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530788 subflow2.SetInPort(inport)
789 subflow2.SetOutPort(outport)
790 subflow2.SetMeterID(vs.UsMeterID)
791
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530792 // refer Table-0 flow generation for byte information
793 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
794 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530795
Naveen Sampath04696f72022-06-13 15:19:14 +0530796 if vs.VlanControl == OLTCVlanOLTSVlan {
797 /**
798 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
799 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
800 * use old cookie.
801 */
802 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
803 if vgcRebooted {
804 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
805 }
806 } else {
807 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
808 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
809 }
810 subflow2.Priority = of.HsiaFlowPriority
811
812 flow.SubFlows[subflow2.Cookie] = subflow2
813 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
814 }
815
816 return flow, nil
817}
818
819func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
820 //| 12-bit cvlan/UniVlan | 4 bits empty | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
821 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
822 cookie = cookie | of.UsFlowMask
823 cookie = cookie + (valToShift << 4) + uint64(pbits)
824 return cookie
825}
826
827// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
828// based on different Vlan Controls
829func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
830 switch vs.VlanControl {
831 case None:
832 flow.SetMatchVlan(vs.SVlan)
833 case ONUCVlanOLTSVlan:
834 flow.SetMatchVlan(vs.CVlan)
835 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
836 case OLTCVlanOLTSVlan:
837 flow.SetMatchVlan(vs.UniVlan)
838 flow.SetSetVlan(vs.CVlan)
839 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
840 case ONUCVlan:
841 flow.SetMatchVlan(vs.SVlan)
842 case OLTSVlan:
843 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
844 flow.SetMatchVlan(vs.UniVlan)
845 flow.SetSetVlan(vs.SVlan)
846 } else if vs.UniVlan != of.VlanNone {
847 flow.SetMatchVlan(vs.UniVlan)
848 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
849 } else {
850 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
851 }
852 default:
853 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
854 return errorCodes.ErrInvalidParamInRequest
855 }
856 return nil
857}
858
859// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
860// based on different Vlan Controls
861func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
862 switch vs.VlanControl {
863 case None:
864 flow.SetMatchVlan(vs.SVlan)
865 case ONUCVlanOLTSVlan:
866 flow.SetMatchVlan(vs.SVlan)
867 flow.SetPopVlan()
868 case OLTCVlanOLTSVlan:
869 flow.SetMatchVlan(vs.SVlan)
870 flow.SetPopVlan()
871 flow.SetSetVlan(vs.UniVlan)
872 case ONUCVlan:
873 flow.SetMatchVlan(vs.SVlan)
874 case OLTSVlan:
875 flow.SetMatchVlan(vs.SVlan)
876 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
877 flow.SetSetVlan(vs.UniVlan)
878 } else {
879 flow.SetPopVlan()
880 }
881 default:
882 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
883 return errorCodes.ErrInvalidParamInRequest
884 }
885 return nil
886}
887
888// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
889// based on different Vlan Controls
890func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
891 switch vs.VlanControl {
892 case None:
893 flow.SetMatchVlan(vs.SVlan)
894 case ONUCVlanOLTSVlan:
895 if vs.UniVlan != of.VlanNone {
896 flow.SetMatchVlan(vs.UniVlan)
897 flow.SetSetVlan(vs.CVlan)
898 } else {
899 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
900 }
901 case OLTCVlanOLTSVlan:
902 flow.SetMatchVlan(vs.UniVlan)
903 case ONUCVlan:
904 if vs.UniVlan != of.VlanNone {
905 flow.SetMatchVlan(vs.UniVlan)
906 flow.SetSetVlan(vs.SVlan)
907 } else {
908 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
909 }
910 case OLTSVlan:
911 flow.SetMatchVlan(vs.UniVlan)
912 default:
913 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
914 return errorCodes.ErrInvalidParamInRequest
915 }
916 return nil
917}
918
919// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
920// based on different Vlan Controls
921func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
922 switch vs.VlanControl {
923 case None:
924 flow.SetMatchVlan(vs.SVlan)
925 case ONUCVlanOLTSVlan:
926 flow.SetMatchVlan(vs.CVlan)
927 if vs.UniVlan != of.VlanNone {
928 flow.SetSetVlan(vs.UniVlan)
929 } else {
930 flow.SetPopVlan()
931 }
932 case OLTCVlanOLTSVlan:
933 flow.SetMatchVlan(vs.UniVlan)
934 case ONUCVlan:
935 flow.SetMatchVlan(vs.SVlan)
936 if vs.UniVlan != of.VlanNone {
937 flow.SetSetVlan(vs.UniVlan)
938 } else {
939 flow.SetPopVlan()
940 }
941 case OLTSVlan:
942 flow.SetMatchVlan(vs.UniVlan)
943 default:
944 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
945 return errorCodes.ErrInvalidParamInRequest
946 }
947 return nil
948}
949
950// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530951func (vs *VoltService) SvcUpInd(cntx context.Context) {
952 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530953}
954
955// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530956func (vs *VoltService) SvcDownInd(cntx context.Context) {
957 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530958}
959
960// SetIpv4Addr to set ipv4 address
961func (vs *VoltService) SetIpv4Addr(addr net.IP) {
962 vs.Ipv4Addr = addr
963}
964
965// SetIpv6Addr to set ipv6 address
966func (vs *VoltService) SetIpv6Addr(addr net.IP) {
967 vs.Ipv6Addr = addr
968}
969
970// SetMacAddr to set mac address
971func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
972 vs.MacAddr = addr
973}
974
975// ----------------------------------------------
976// VOLT Application - Related to services
977// ---------------------------------------------
978// ---------------------------------------------------------------
979// Service CRUD functions. These are exposed to the overall binary
980// to be invoked from the point where the CRUD operations are received
981// from the external entities
982
983// AddService : A service in the context of VOLT is a subscriber or service of a
984// subscriber which is uniquely identified by a combination of MAC
985// address, VLAN tags, 802.1p bits. However, in the context of the
986// current implementation, a service is an entity that is identified by a
987// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
988// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530989func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530990 var mmUs, mmDs *VoltMeter
991 var err error
992
993 //Take the Device lock only in case of NB add request.
994 // Allow internal adds since internal add happen only under
995 // 1. Restore Service from DB
996 // 2. Service Migration
997 if oper == nil {
998 if svc := va.GetService(cfg.Name); svc != nil {
999 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
1000 return errors.New("Service Already Exists")
1001 }
1002 }
1003
1004 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
1005 // Service doesn't exist. So create it and add to the port
1006 vs := NewVoltService(&cfg)
1007 if oper != nil {
1008 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1009 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1010 vs.Ipv4Addr = oper.Ipv4Addr
1011 vs.Ipv6Addr = oper.Ipv6Addr
1012 vs.MacLearning = cfg.MacLearning
1013 vs.PendingFlows = oper.PendingFlows
1014 vs.AssociatedFlows = oper.AssociatedFlows
1015 vs.DeleteInProgress = oper.DeleteInProgress
1016 vs.BwAvailInfo = oper.BwAvailInfo
1017 vs.Device = oper.Device
1018 } else {
1019
1020 //Sorting Pbit from highest
1021 sort.Slice(vs.Pbits, func(i, j int) bool {
1022 return vs.Pbits[i] > vs.Pbits[j]
1023 })
1024 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1025 }
1026 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1027
1028 // The bandwidth and shaper profile combined into meter
1029 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1030 vs.DsMeterID = mmDs.ID
1031 } else {
1032 return errors.New("DownStream meter profile not found")
1033 }
1034
1035 // The aggregated downstream meter profile
1036 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1037 // vs.AggDsMeterID = mmAg.ID
1038 // } else {
1039 // return errors.New("Aggregated meter profile not found")
1040 // }
1041
1042 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1043 // vs.UsMeterID = mmAg.ID
1044 // } else {
1045 // The bandwidth and shaper profile combined into meter
1046 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1047 vs.UsMeterID = mmUs.ID
1048 } else {
1049 return errors.New("Upstream meter profile not found")
1050 }
1051 //}
1052
1053 AppMutex.ServiceDataMutex.Lock()
1054 defer AppMutex.ServiceDataMutex.Unlock()
1055
1056 // Add the service to the VNET
1057 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1058 if vnet != nil {
1059 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1060 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301061 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301062 vpv.VpvLock.Unlock()
1063 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301064 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301065 }
1066 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301067 logger.Errorw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301068 return errors.New("VNET doesn't exist")
1069 }
1070
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301071 // If the device is already discovered, update the device name in service
1072 d, err := va.GetDeviceFromPort(vs.Port)
1073 if err == nil {
1074 vs.Device = d.Name
1075 }
1076
Naveen Sampath04696f72022-06-13 15:19:14 +05301077 vs.Version = database.PresentVersionMap[database.ServicePath]
1078 // Add the service to the volt application
1079 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301080 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301081
1082 if nil == oper {
1083
1084 if !vs.UsHSIAFlowsApplied {
1085 vs.triggerServiceInProgressInd()
1086 }
1087
1088 //Update meter profiles service count if service is being added from northbound
1089 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301090 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301091 if mmUs != nil {
1092 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301093 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301094 }
1095 //mmAg.AssociatedServices++
1096 //va.UpdateMeterProf(*mmAg)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301097 logger.Debugw(ctx, "northbound-service-add-sucessful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301098 }
1099
1100 logger.Warnw(ctx, "Added Service to DB", log.Fields{"Name": vs.Name, "Port": (vs.Port), "ML": vs.MacLearning})
1101 return nil
1102}
1103
1104//DelServiceWithPrefix - Deletes service with the provided prefix.
1105// Added for DT/TT usecase with sadis replica interface
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301106func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301107 va.ServiceByName.Range(func(key, value interface{}) bool {
1108 srvName := key.(string)
1109 vs := value.(*VoltService)
1110 if strings.Contains(srvName, prefix) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301111 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301112
1113 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1114 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1115 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1116
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301117 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301118 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1119 }
1120 }
1121 return true
1122 })
1123}
1124
1125// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301126func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301127
1128 AppMutex.ServiceDataMutex.Lock()
1129 defer AppMutex.ServiceDataMutex.Unlock()
1130
1131 logger.Warnw(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
1132 var noFlowsPresent bool
1133
1134 vsIntf, ok := va.ServiceByName.Load(name)
1135 if !ok {
1136 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1137 return
1138 }
1139 vs := vsIntf.(*VoltService)
1140 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1141 if vpv == nil {
1142 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
1143 return
1144 }
1145
1146 //Set this to avoid race-condition during flow result processing
1147 vs.DeleteInProgress = true
1148 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301149 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301150
1151 if len(vs.AssociatedFlows) == 0 {
1152 noFlowsPresent = true
1153 }
1154 vpv.VpvLock.Lock()
1155 defer vpv.VpvLock.Unlock()
1156
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301157 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301158
1159 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301160 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301161 }
1162 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 +05301163 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301164 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301165 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301166 }
1167
1168 // Delete the service immediately in case of Force Delete
1169 // This will be enabled when profile reconciliation happens after restore
1170 // of backedup data
1171 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301172 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301173 GetApplication().ServiceByName.Delete(vs.Name)
1174 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1175 }
1176
1177 meterProfiles := make(map[*VoltMeter]bool)
1178
1179 if nil != newSvc {
1180 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1181 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1182 }
1183 skipMeterDeletion := false
1184 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1185 if nil != newSvc && aggMeter.Name == newSvc.AggDsMeterProfile {
1186 skipMeterDeletion = true
1187 }
1188
1189 meterProfiles[aggMeter] = skipMeterDeletion
1190 skipMeterDeletion = false
1191 }
1192 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
1193 if nil != newSvc && dsMeter.Name == newSvc.DsMeterProfile {
1194 skipMeterDeletion = true
1195 }
1196 meterProfiles[dsMeter] = skipMeterDeletion
1197 skipMeterDeletion = false
1198 }
1199 if vs.AggDsMeterID != vs.UsMeterID {
1200 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
1201 if nil != newSvc && usMeter.Name == newSvc.UsMeterProfile {
1202 skipMeterDeletion = true
1203 }
1204 meterProfiles[usMeter] = skipMeterDeletion
1205 }
1206 }
1207
1208 for meter, skipMeterDeletion := range meterProfiles {
1209 if nil == meter {
1210 logger.Debug(ctx, "Null meter found, continuing")
1211 continue
1212 }
1213 if meter.AssociatedServices > 0 {
1214 meter.AssociatedServices--
1215 if meter.AssociatedServices == 0 && !skipMeterDeletion {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301216 logger.Infow(ctx, "Meter should be deleted now\n", log.Fields{"MeterID": meter})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301217 va.UpdateMeterProf(cntx, *meter)
Naveen Sampath04696f72022-06-13 15:19:14 +05301218 }
1219 }
1220 }
1221
1222 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301223 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301224 }
1225
1226 //Delete the per service counter too
1227 va.ServiceCounters.Delete(name)
1228 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301229 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301230 }
1231}
1232
1233//AddFlows - Adds the flow to the service
1234// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301235func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301236
1237 // Using locks instead of concurrent map for PendingFlows to avoid
1238 // race condition during flow response indication processing
1239 vs.ServiceLock.Lock()
1240 defer vs.ServiceLock.Unlock()
1241
1242 for cookie := range flow.SubFlows {
1243 cookie := strconv.FormatUint(cookie, 10)
1244 fe := &FlowEvent{
1245 eType: EventTypeServiceFlowAdded,
1246 device: device.Name,
1247 cookie: cookie,
1248 eventData: vs,
1249 }
1250 device.RegisterFlowAddEvent(cookie, fe)
1251 vs.PendingFlows[cookie] = true
1252 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301253 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301254}
1255
1256//FlowInstallSuccess - Called when corresponding service flow installation is success
1257// If no more pending flows, HSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301258func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301259 if vs.DeleteInProgress {
1260 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1261 return
1262 }
1263 vs.ServiceLock.Lock()
1264
1265 if _, ok := vs.PendingFlows[cookie]; !ok {
1266 logger.Errorw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1267 vs.ServiceLock.Unlock()
1268 return
1269 }
1270
1271 delete(vs.PendingFlows, cookie)
1272 vs.AssociatedFlows[cookie] = true
1273 vs.ServiceLock.Unlock()
1274 var prevBwAvail, presentBwAvail string
1275 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1276 prevBwAvail = bwAvailInfo.PrevBw
1277 presentBwAvail = bwAvailInfo.PresentBw
1278 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301279 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301280 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301281 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301282
1283 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
1284
1285 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1286 if err != nil {
1287 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1288 return
1289 } else if device.State != controller.DeviceStateUP {
1290 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1291 return
1292 }
1293
1294 if vs.Trigger == ServiceVlanUpdate {
1295 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301296 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301297 }
1298 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1299 return
1300 }
1301 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1302}
1303
1304//FlowInstallFailure - Called when corresponding service flow installation is failed
1305// Trigger service failure indication to NB
1306func (vs *VoltService) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
1307 vs.ServiceLock.RLock()
1308
1309 if _, ok := vs.PendingFlows[cookie]; !ok {
1310 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1311 vs.ServiceLock.RUnlock()
1312 return
1313 }
1314 vs.ServiceLock.RUnlock()
1315 logger.Errorw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1316 vs.triggerServiceFailureInd(errorCode, errReason)
1317}
1318
1319//DelFlows - Deletes the flow from the service
1320// Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301321func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301322
1323 if !vs.ForceDelete {
1324 // Using locks instead of concurrent map for AssociatedFlows to avoid
1325 // race condition during flow response indication processing
1326 vs.ServiceLock.Lock()
1327 defer vs.ServiceLock.Unlock()
1328
1329 for cookie := range flow.SubFlows {
1330 cookie := strconv.FormatUint(cookie, 10)
1331 fe := &FlowEvent{
1332 eType: EventTypeServiceFlowRemoved,
1333 cookie: cookie,
1334 eventData: vs,
1335 }
1336 device.RegisterFlowDelEvent(cookie, fe)
1337 }
1338 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301339 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301340}
1341
1342//CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301343func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301344 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301345 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301346 GetApplication().ServiceByName.Delete(vs.Name)
1347 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1348 }
1349}
1350
1351//FlowRemoveSuccess - Called when corresponding service flow removal is success
1352// If no more associated flows, DelHSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301353func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301354
1355 // if vs.DeleteInProgress {
1356 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1357 // return
1358 // }
1359 vs.ServiceLock.Lock()
1360 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1361
1362 if _, ok := vs.AssociatedFlows[cookie]; ok {
1363 delete(vs.AssociatedFlows, cookie)
1364 } else if _, ok := vs.PendingFlows[cookie]; ok {
1365 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})
1366 } else {
1367 logger.Errorw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
1368 }
1369
1370 vs.ServiceLock.Unlock()
1371
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301372 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301373
1374 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
1375
1376 device := GetApplication().GetDevice(vs.Device)
1377 if device == nil {
1378 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1379 return
1380 } else if device.State != controller.DeviceStateUP {
1381 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1382 return
1383 }
1384
1385 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301386 vs.updateVnetProfile(cntx, vs.Device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301387 //Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
1388 return
1389 }
1390 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 +05301391 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301392
1393 return
1394 }
1395 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1396}
1397
1398//FlowRemoveFailure - Called when corresponding service flow installation is failed
1399// Trigger service failure indication to NB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301400func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301401 vs.ServiceLock.RLock()
1402
1403 if _, ok := vs.AssociatedFlows[cookie]; !ok {
1404 logger.Errorw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1405 vs.ServiceLock.RUnlock()
1406 return
1407 }
1408 if vs.DeleteInProgress {
1409 delete(vs.AssociatedFlows, cookie)
1410 }
1411 vs.ServiceLock.RUnlock()
1412 logger.Errorw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1413
1414 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301415 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301416}
1417
1418func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
1419 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1420 if err != nil {
1421 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1422 return
1423 } else if device.State != controller.DeviceStateUP {
1424 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1425 return
1426 }
1427}
1428
1429// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301430func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301431 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301432 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301433 for _, vs := range vss {
1434 b, ok := vs.Value.([]byte)
1435 if !ok {
1436 logger.Warn(ctx, "The value type is not []byte")
1437 continue
1438 }
1439 var vvs VoltService
1440 err := json.Unmarshal(b, &vvs)
1441 if err != nil {
1442 logger.Warn(ctx, "Unmarshal of VNET failed")
1443 continue
1444 }
1445 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301446 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301447 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1448 }
1449
1450 if vvs.VoltServiceOper.DeleteInProgress {
1451 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1452 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1453 }
1454 }
1455}
1456
1457// GetService to get service
1458func (va *VoltApplication) GetService(name string) *VoltService {
1459 if vs, ok := va.ServiceByName.Load(name); ok {
1460 return vs.(*VoltService)
1461 }
1462 return nil
1463}
1464
1465// GetCircuitID to get circuit id
1466func (vs *VoltService) GetCircuitID() []byte {
1467 return []byte(vs.CircuitID)
1468}
1469
1470// GetRemoteID to get remote id
1471func (vs *VoltService) GetRemoteID() []byte {
1472 return []byte(vs.RemoteID)
1473}
1474
1475// IPAssigned to check if ip is assigned
1476func (vs *VoltService) IPAssigned() bool {
1477 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1478 return true
1479 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1480 return true
1481 }
1482 return false
1483}
1484
1485// GetServiceNameFromCookie to get service name from cookie
1486func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
1487
1488 var vlan uint64
1489 vlanControl := (tableMetadata >> 32) & 0xF
1490
1491 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1492 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1493 vlan = (tableMetadata >> 16) & 0xFFFF
1494 } else {
1495 //Fetching CVlan for other vlanControl
1496 vlan = cookie >> 52
1497 }
1498 logger.Infow(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
1499 var vlans []of.VlanType
1500 vlans = append(vlans, of.VlanType(vlan))
1501 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1502 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301503 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301504 } else {
1505 logger.Errorw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
1506 }
1507 return service
1508}
1509
1510//MigrateServicesReqStatus - update vnet request status
1511type MigrateServicesReqStatus string
1512
1513const (
1514 //MigrateSrvsReqInit constant
1515 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
1516 //MigrateSrvsReqDeactTriggered constant
1517 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
1518 //MigrateSrvsReqCompleted constant
1519 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1520)
1521
1522//MigrateServicesRequest - update vnet request params
1523type MigrateServicesRequest struct {
1524 ID string
1525 OldVnetID string
1526 NewVnetID string
1527 ServicesList map[string]bool
1528 DeviceID string
1529 Status MigrateServicesReqStatus
1530 MigrateServicesLock sync.RWMutex
1531}
1532
1533func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
1534
1535 var msr MigrateServicesRequest
1536 msr.OldVnetID = oldVnetID
1537 msr.NewVnetID = newVnetID
1538 msr.ID = id
1539 msr.ServicesList = serviceMap
1540 msr.DeviceID = deviceID
1541 msr.Status = MigrateSrvsReqInit
1542 return &msr
1543}
1544
1545//GetMsrKey - generates migrate service request key
1546func (msr *MigrateServicesRequest) GetMsrKey() string {
1547 return msr.OldVnetID + "-" + msr.ID
1548}
1549
1550// //isRequestComplete - return if all request has been processed and completed
1551// // RequestProcessed indicates that all the profile de-activation has been triggered
1552// // And the associated profiles indicates the profiles awaiting results
1553// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1554// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1555// return (len(edr.AssociatedProfiles) == 0)
1556// }
1557
1558//WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301559func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301560 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)})
1561 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301562 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301563 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301564 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301565 }
1566 }
1567}
1568
1569//MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301570func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301571
1572 logger.Warnw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
1573 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
1574 return errors.New("Old Vnet Id not found")
1575 }
1576 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
1577 return errors.New("New Vnet Id not found")
1578 }
1579
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301580 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301581 if d == nil {
1582 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1583 return errorCodes.ErrDeviceNotFound
1584 }
1585
1586 serviceMap := make(map[string]bool)
1587
1588 for _, service := range serviceList {
1589 serviceMap[service] = false
1590 }
1591 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301592 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301593
1594 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301595 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301596 return nil
1597}
1598
1599//ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301600func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301601 va := GetApplication()
1602 for srv, processed := range msr.ServicesList {
1603
1604 //Indicates new service is already created and only deletion of old one is pending
1605 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301606 va.DelService(cntx, srv, true, nil, true)
1607 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301608 continue
1609 }
1610
1611 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1612 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1613 vs := vsIntf.(*VoltService)
1614 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1615 if vpv == nil {
1616 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
1617 continue
1618 }
1619 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1620 vpv.Blocked = true
1621
1622 // setDeactTrigger := func(key, value interface{}) bool {
1623 // vs := value.(*VoltService)
1624 vs.ServiceLock.Lock()
1625 vs.UpdateInProgress = true
1626 metadata := &MigrateServiceMetadata{
1627 NewVnetID: msr.NewVnetID,
1628 RequestID: msr.ID,
1629 }
1630 vs.Metadata = metadata
1631 vs.ServiceLock.Unlock()
1632
1633 //vpv flows will be removed when last service is removed from it and
1634 // new vpv flows will be installed when new service is added
1635 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301636 vpv.DelTrapFlows(cntx)
1637 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301638 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301639 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301640 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301641 }
1642 } else {
1643 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1644 }
1645 }
1646}
1647
1648//AddMigratingServices - store msr info to device obj
1649func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
1650
1651 var msrMap *util.ConcurrentMap
1652 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1653 msrMap = util.NewConcurrentMap()
1654 } else {
1655 msrMap = msrMapIntf.(*util.ConcurrentMap)
1656 }
1657
1658 msrMap.Set(msr.ID, msr)
1659 logger.Infow(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
1660
1661 d.MigratingServices.Set(msr.OldVnetID, msrMap)
1662 logger.Infow(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
1663
1664}
1665
1666//getMigrateServicesRequest - fetches msr info from device
1667func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
1668 if vd := va.GetDevice(deviceID); vd != nil {
1669 logger.Infow(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
1670 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1671 msrList := msrListIntf.(*util.ConcurrentMap)
1672 logger.Infow(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
1673 if msrObj, ok := msrList.Get(requestID); ok {
1674 return msrObj.(*MigrateServicesRequest)
1675 }
1676
1677 }
1678 }
1679 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
1680 return nil
1681}
1682
1683//updateMigrateServicesRequest - Updates the device with updated msr
1684func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
1685 if vd := va.GetDevice(deviceID); vd != nil {
1686 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1687 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1688 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1689 }
1690 }
1691 }
1692}
1693
1694//updateVnetProfile - Called on flow process completion
1695// Removes old service and creates new VPV & service with udpated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301696func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301697
Tinoj Joseph1d108322022-07-13 10:07:39 +05301698 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 +05301699
1700 nvs := VoltService{}
1701 nvs.VoltServiceCfg = vs.VoltServiceCfg
1702 nvs.Device = vs.Device
1703 nvs.Ipv4Addr = vs.Ipv4Addr
1704 nvs.Ipv6Addr = vs.Ipv6Addr
1705 nvs.UsMeterID = vs.UsMeterID
1706 nvs.DsMeterID = vs.DsMeterID
1707 nvs.AggDsMeterID = vs.AggDsMeterID
1708 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1709 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1710 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1711 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1712 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1713 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1714 nvs.PendingFlows = vs.PendingFlows
1715 nvs.AssociatedFlows = vs.AssociatedFlows
1716 nvs.DeleteInProgress = vs.DeleteInProgress
1717 nvs.ForceDelete = vs.ForceDelete
1718 nvs.BwAvailInfo = vs.BwAvailInfo
1719 nvs.UpdateInProgress = vs.UpdateInProgress
1720
1721 if nvs.DeleteInProgress {
1722 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1723 return
1724 }
1725
1726 metadata := vs.Metadata.(*MigrateServiceMetadata)
1727 oldVnetID := vs.VnetID
1728 nvs.VnetID = metadata.NewVnetID
1729 id := metadata.RequestID
1730 oldSrvName := vs.Name
1731
1732 if metadata == nil || metadata.NewVnetID == "" {
1733 logger.Errorw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
1734 return
1735 }
1736
1737 //First add the new service and then only delete the old service
1738 // Since if post del service in case of pod crash or reboot, the service data will be lost
1739 va := GetApplication()
1740 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1741 vnets := strings.Split(metadata.NewVnetID, "-")
1742 svlan, _ := strconv.Atoi(vnets[0])
1743 nvs.SVlan = of.VlanType(svlan)
1744 nvs.UpdateInProgress = false
1745 nvs.Metadata = nil
1746 nvs.Trigger = ServiceVlanUpdate
1747
1748 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1749 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1750 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1751
1752 //TODO:Nav Pass a copy, not the pointer
1753 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 +05301754 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301755 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1756 }
1757 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1758
1759 msr.ServicesList[oldSrvName] = true
1760 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301761 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301762
1763 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 +05301764 va.DelService(cntx, oldSrvName, true, nil, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301765 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 +05301766 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301767}
1768
1769//serviceMigrated - called on successful service updation
1770// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301771func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301772
1773 msr.MigrateServicesLock.Lock()
1774 defer msr.MigrateServicesLock.Unlock()
1775
1776 delete(msr.ServicesList, serviceName)
1777
1778 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301779 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301780 return
1781 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301782 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301783 //TODO:Nav - Need for any Response to SubMgr?
1784}
1785
1786//TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301787func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1788 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301789}
1790
1791//FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301792func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301793
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301794 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301795 for _, msr := range msrList {
1796 b, ok := msr.Value.([]byte)
1797 if !ok {
1798 logger.Warn(ctx, "The value type is not []byte")
1799 continue
1800 }
1801 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301802 msrAction(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301803 logger.Warnw(ctx, "Triggering Pending Migrate Services Req", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID, "Device": device, "PendingProfiles": len(msr.ServicesList)})
1804
1805 }
1806}
1807
1808// createMigrateServicesFromString to create Service from string
1809func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
1810 var msr MigrateServicesRequest
1811 if err := json.Unmarshal(b, &msr); err == nil {
1812 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
1813
1814 } else {
1815 logger.Warn(ctx, "Unmarshal failed")
1816 }
1817 return &msr
1818}
1819
1820//storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301821func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301822 d := GetApplication().GetDevice(msr.DeviceID)
1823 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301824 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301825}
1826
1827//forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301828func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301829 for srv := range msr.ServicesList {
1830 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301831 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301832 }
1833 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301834 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301835}
1836
1837//DeepEqualServicecfg - checks if the given service cfgs are same
1838func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1839 if nvs.Name != evs.Name {
1840 return false
1841 }
1842 if nvs.UniVlan != evs.UniVlan {
1843 return false
1844 }
1845 if nvs.CVlan != evs.CVlan {
1846 return false
1847 }
1848 if nvs.SVlan != evs.SVlan {
1849 return false
1850 }
1851 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1852 return false
1853 }
1854 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1855 return false
1856 }
1857 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1858 return false
1859 }
1860 if nvs.TechProfileID != evs.TechProfileID {
1861 return false
1862 }
1863 if nvs.CircuitID != evs.CircuitID {
1864 return false
1865 }
1866 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1867 return false
1868 }
1869 if nvs.Port != evs.Port {
1870 return false
1871 }
1872 if nvs.PonPort != evs.PonPort {
1873 return false
1874 }
1875 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1876 return false
1877 }
1878 if nvs.IsOption82Disabled != evs.IsOption82Disabled {
1879 return false
1880 }
1881 if nvs.IgmpEnabled != evs.IgmpEnabled {
1882 return false
1883 }
1884 if nvs.McastService != evs.McastService {
1885 return false
1886 }
1887 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1888 return false
1889 }
1890 if nvs.UsMeterProfile != evs.UsMeterProfile {
1891 return false
1892 }
1893 if nvs.DsMeterProfile != evs.DsMeterProfile {
1894 return false
1895 }
1896 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
1897 return false
1898 }
1899 if nvs.VnetID != evs.VnetID {
1900 return false
1901 }
1902 if nvs.MvlanProfileName != evs.MvlanProfileName {
1903 return false
1904 }
1905 if nvs.RemoteIDType != evs.RemoteIDType {
1906 return false
1907 }
1908 if nvs.SchedID != evs.SchedID {
1909 return false
1910 }
1911 if nvs.AllowTransparent != evs.AllowTransparent {
1912 return false
1913 }
1914 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
1915 return false
1916 }
1917 if nvs.DataRateAttr != evs.DataRateAttr {
1918 return false
1919 }
1920 if nvs.MinDataRateUs != evs.MinDataRateUs {
1921 return false
1922 }
1923 if nvs.MinDataRateDs != evs.MinDataRateDs {
1924 return false
1925 }
1926 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
1927 return false
1928 }
1929 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
1930 return false
1931 }
1932
1933 return true
1934}
1935
1936//TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301937func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301938
1939 //Clear the Flows flag if already set
1940 //This case happens only in case of some race condition
1941 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301942 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301943 logger.Errorw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1944 }
1945 }
1946
1947 if vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301948 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301949 logger.Errorw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1950 }
1951 }
1952
1953 vs.ServiceLock.Lock()
1954 cookieList := []uint64{}
1955 for cookie := range vs.AssociatedFlows {
1956 cookieList = append(cookieList, convertToUInt64(cookie))
1957 }
1958 vs.ServiceLock.Unlock()
1959
1960 if len(cookieList) == 0 {
1961 return false
1962 }
1963
1964 //Trigger Flow Delete
1965 for _, cookie := range cookieList {
1966 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
1967 flow := &of.VoltFlow{}
1968 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1969 subFlow := of.NewVoltSubFlow()
1970 subFlow.Cookie = cookie
1971 flow.SubFlows[cookie] = subFlow
1972 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301973 if err := vs.DelFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301974 logger.Errorw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
1975 }
1976 }
1977 }
1978 return true
1979}
1980
1981//triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
1982func (vs *VoltService) triggerServiceInProgressInd() {
1983}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301984
1985// JsonMarshal wrapper function for json Marshal VoltService
1986func (vs *VoltService) JsonMarshal() ([]byte, error) {
1987 return json.Marshal(VoltService{
1988 VoltServiceCfg: vs.VoltServiceCfg,
1989 VoltServiceOper: VoltServiceOper{
1990 Device: vs.VoltServiceOper.Device,
1991 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
1992 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
1993 UsMeterID: vs.VoltServiceOper.UsMeterID,
1994 DsMeterID: vs.VoltServiceOper.DsMeterID,
1995 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
1996 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
1997 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
1998 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
1999 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
2000 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
2001 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
2002 PendingFlows: vs.VoltServiceOper.PendingFlows,
2003 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
2004 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2005 ForceDelete: vs.VoltServiceOper.ForceDelete,
2006 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2007 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2008 Metadata: vs.VoltServiceOper.Metadata,
2009 },
2010 })
2011}
Tinoj Josephec742f62022-09-29 19:11:10 +05302012
2013// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302014func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302015 var svcList []*VoltService
2016 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2017 va.ServiceByName.Range(func(key, value interface{}) bool {
2018 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302019 if len(deviceID) > 0 {
2020 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302021 if deviceID == vs.Device && portNo == vs.Port {
2022 svcList = append(svcList, vs)
2023 }
2024 } else {
2025 if deviceID == vs.Device {
2026 svcList = append(svcList, vs)
2027 }
2028 }
2029 } else {
2030 svcList = append(svcList, vs)
2031 }
2032 return true
2033 })
2034 return svcList, nil
2035}
2036
2037// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302038func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302039 logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302040 device, err := va.GetDeviceFromPort(portNo)
2041 if err != nil {
2042 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2043 return errorCodes.ErrPortNotFound
2044 }
2045 // If device id is not provided check only port number
2046 if deviceID == DeviceAny {
2047 deviceID = device.Name
2048 } else if deviceID != device.Name {
2049 logger.Errorw(ctx, "Wrong Device ID", log.Fields{"Device": deviceID, "Port": portNo})
2050 return errorCodes.ErrDeviceNotFound
2051 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302052 va.ServiceByName.Range(func(key, value interface{}) bool {
2053 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302054 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302055 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302056 logger.Infow(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302057 return true
2058 }
2059 if portNo == vs.Port && !vs.IsActivated {
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302060 p := device.GetPort(vs.Port)
Tinoj Josephec742f62022-09-29 19:11:10 +05302061 if p == nil {
2062 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2063 return true
2064 }
2065 logger.Infow(ctx, "Service Activate", log.Fields{"Name": vs.Name})
2066 vs.IsActivated = true
2067 va.ServiceByName.Store(vs.Name, vs)
2068 vs.WriteToDb(cntx)
2069 // If port is already up send indication to vpv
2070 if p.State == PortStateUp {
2071 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2072 // PortUp call initiates flow addition
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302073 vpv.PortUpInd(cntx, device, portNo)
Tinoj Josephec742f62022-09-29 19:11:10 +05302074 } else {
2075 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2076 }
2077 }
2078 }
2079 return true
2080 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302081 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302082}
2083
2084// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302085func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302086 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2087 va.ServiceByName.Range(func(key, value interface{}) bool {
2088 vs := value.(*VoltService)
2089 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302090 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2091 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
2092 logger.Infow(ctx, "condition not matched", log.Fields{"Device": deviceID, "Port": portNo, "sVlan": sVlan, "cVlan":cVlan, "tpID": tpID})
Tinoj Josephec742f62022-09-29 19:11:10 +05302093 return true
2094 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302095 if portNo == vs.Port && vs.IsActivated {
Tinoj Josephec742f62022-09-29 19:11:10 +05302096 vs.IsActivated = false
2097 va.ServiceByName.Store(vs.Name, vs)
2098 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302099 device, err := va.GetDeviceFromPort(portNo)
2100 if err != nil {
2101 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2102 // So no error is returned
2103 logger.Infow(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2104 return true
2105 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302106 p := device.GetPort(vs.Port)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302107 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable){
Tinoj Josephec742f62022-09-29 19:11:10 +05302108 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2109 // Port down call internally deletes all the flows
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302110 vpv.PortDownInd(cntx, deviceID, portNo, true)
Tinoj Josephec742f62022-09-29 19:11:10 +05302111 if vpv.IgmpEnabled {
2112 va.ReceiverDownInd(cntx, deviceID, portNo)
2113 }
2114 } else {
2115 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2116 }
2117 }
2118 }
2119 return true
2120 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302121 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302122}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302123
Tinoj Josephec742f62022-09-29 19:11:10 +05302124/* GetServicePbit to get first set bit in the pbit map
2125 returns -1 : If configured to match on all pbits
2126 returns 8 : If no pbits are configured
2127 returns first pbit if specific pbit is configured */
2128func (vs *VoltService) GetServicePbit() int {
2129 if vs.IsPbitExist(of.PbitMatchAll) {
2130 return -1
2131 }
2132 for pbit:= 0; pbit < int(of.PbitMatchNone); pbit++ {
2133 if vs.IsPbitExist(of.PbitType(pbit)) {
2134 return pbit
2135 }
2136 }
2137 return int(of.PbitMatchNone)
2138}