blob: e129b48b97566baa0f28bced4edfa1d71bc3a4d4 [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
Naveen Sampath04696f72022-06-13 15:19:14 +05301177 if nil != newSvc {
1178 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1179 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1180 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301181
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301182 logger.Infow(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
1183
1184 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1185 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
1186 if aggMeter.AssociatedServices > 0 {
1187 aggMeter.AssociatedServices--
1188 logger.Infow(ctx, "Agg Meter assocaited services updated\n", log.Fields{"MeterID": aggMeter})
1189 va.UpdateMeterProf(cntx, *aggMeter)
1190 }
1191 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301192 }
1193 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301194 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1195 if dsMeter.AssociatedServices > 0 {
1196 dsMeter.AssociatedServices--
1197 logger.Infow(ctx, "DS Meter assocaited services updated\n", log.Fields{"MeterID": dsMeter})
1198 va.UpdateMeterProf(cntx, *dsMeter)
1199 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301200 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301201 }
1202 if vs.AggDsMeterID != vs.UsMeterID {
1203 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301204 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1205 if usMeter.AssociatedServices > 0 {
1206 usMeter.AssociatedServices--
1207 logger.Infow(ctx, "US Meter assocaited services updated\n", log.Fields{"MeterID": usMeter})
1208 va.UpdateMeterProf(cntx, *usMeter)
1209 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301210 }
1211 }
1212 }
1213
1214 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301215 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301216 }
1217
1218 //Delete the per service counter too
1219 va.ServiceCounters.Delete(name)
1220 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301221 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301222 }
1223}
1224
1225//AddFlows - Adds the flow to the service
1226// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301227func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301228
1229 // Using locks instead of concurrent map for PendingFlows to avoid
1230 // race condition during flow response indication processing
1231 vs.ServiceLock.Lock()
1232 defer vs.ServiceLock.Unlock()
1233
1234 for cookie := range flow.SubFlows {
1235 cookie := strconv.FormatUint(cookie, 10)
1236 fe := &FlowEvent{
1237 eType: EventTypeServiceFlowAdded,
1238 device: device.Name,
1239 cookie: cookie,
1240 eventData: vs,
1241 }
1242 device.RegisterFlowAddEvent(cookie, fe)
1243 vs.PendingFlows[cookie] = true
1244 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301245 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301246}
1247
1248//FlowInstallSuccess - Called when corresponding service flow installation is success
1249// If no more pending flows, HSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301250func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301251 if vs.DeleteInProgress {
1252 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1253 return
1254 }
1255 vs.ServiceLock.Lock()
1256
1257 if _, ok := vs.PendingFlows[cookie]; !ok {
1258 logger.Errorw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1259 vs.ServiceLock.Unlock()
1260 return
1261 }
1262
1263 delete(vs.PendingFlows, cookie)
1264 vs.AssociatedFlows[cookie] = true
1265 vs.ServiceLock.Unlock()
1266 var prevBwAvail, presentBwAvail string
1267 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1268 prevBwAvail = bwAvailInfo.PrevBw
1269 presentBwAvail = bwAvailInfo.PresentBw
1270 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301271 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301272 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301273 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301274
1275 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
1276
1277 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1278 if err != nil {
1279 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1280 return
1281 } else if device.State != controller.DeviceStateUP {
1282 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1283 return
1284 }
1285
1286 if vs.Trigger == ServiceVlanUpdate {
1287 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301288 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301289 }
1290 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1291 return
1292 }
1293 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1294}
1295
1296//FlowInstallFailure - Called when corresponding service flow installation is failed
1297// Trigger service failure indication to NB
1298func (vs *VoltService) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
1299 vs.ServiceLock.RLock()
1300
1301 if _, ok := vs.PendingFlows[cookie]; !ok {
1302 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1303 vs.ServiceLock.RUnlock()
1304 return
1305 }
1306 vs.ServiceLock.RUnlock()
1307 logger.Errorw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1308 vs.triggerServiceFailureInd(errorCode, errReason)
1309}
1310
1311//DelFlows - Deletes the flow from the service
1312// Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301313func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301314
1315 if !vs.ForceDelete {
1316 // Using locks instead of concurrent map for AssociatedFlows to avoid
1317 // race condition during flow response indication processing
1318 vs.ServiceLock.Lock()
1319 defer vs.ServiceLock.Unlock()
1320
1321 for cookie := range flow.SubFlows {
1322 cookie := strconv.FormatUint(cookie, 10)
1323 fe := &FlowEvent{
1324 eType: EventTypeServiceFlowRemoved,
1325 cookie: cookie,
1326 eventData: vs,
1327 }
1328 device.RegisterFlowDelEvent(cookie, fe)
1329 }
1330 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301331 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301332}
1333
1334//CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301335func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301336 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301337 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301338 GetApplication().ServiceByName.Delete(vs.Name)
1339 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1340 }
1341}
1342
1343//FlowRemoveSuccess - Called when corresponding service flow removal is success
1344// If no more associated flows, DelHSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301345func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301346
1347 // if vs.DeleteInProgress {
1348 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1349 // return
1350 // }
1351 vs.ServiceLock.Lock()
1352 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1353
1354 if _, ok := vs.AssociatedFlows[cookie]; ok {
1355 delete(vs.AssociatedFlows, cookie)
1356 } else if _, ok := vs.PendingFlows[cookie]; ok {
1357 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})
1358 } else {
1359 logger.Errorw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
1360 }
1361
1362 vs.ServiceLock.Unlock()
1363
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301364 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301365
1366 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
1367
1368 device := GetApplication().GetDevice(vs.Device)
1369 if device == nil {
1370 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1371 return
1372 } else if device.State != controller.DeviceStateUP {
1373 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1374 return
1375 }
1376
1377 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301378 vs.updateVnetProfile(cntx, vs.Device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301379 //Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
1380 return
1381 }
1382 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 +05301383 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301384
1385 return
1386 }
1387 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1388}
1389
1390//FlowRemoveFailure - Called when corresponding service flow installation is failed
1391// Trigger service failure indication to NB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301392func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301393 vs.ServiceLock.RLock()
1394
1395 if _, ok := vs.AssociatedFlows[cookie]; !ok {
1396 logger.Errorw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1397 vs.ServiceLock.RUnlock()
1398 return
1399 }
1400 if vs.DeleteInProgress {
1401 delete(vs.AssociatedFlows, cookie)
1402 }
1403 vs.ServiceLock.RUnlock()
1404 logger.Errorw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1405
1406 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301407 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301408}
1409
1410func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
1411 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1412 if err != nil {
1413 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1414 return
1415 } else if device.State != controller.DeviceStateUP {
1416 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1417 return
1418 }
1419}
1420
1421// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301422func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301423 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301424 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301425 for _, vs := range vss {
1426 b, ok := vs.Value.([]byte)
1427 if !ok {
1428 logger.Warn(ctx, "The value type is not []byte")
1429 continue
1430 }
1431 var vvs VoltService
1432 err := json.Unmarshal(b, &vvs)
1433 if err != nil {
1434 logger.Warn(ctx, "Unmarshal of VNET failed")
1435 continue
1436 }
1437 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301438 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301439 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1440 }
1441
1442 if vvs.VoltServiceOper.DeleteInProgress {
1443 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1444 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1445 }
1446 }
1447}
1448
1449// GetService to get service
1450func (va *VoltApplication) GetService(name string) *VoltService {
1451 if vs, ok := va.ServiceByName.Load(name); ok {
1452 return vs.(*VoltService)
1453 }
1454 return nil
1455}
1456
1457// GetCircuitID to get circuit id
1458func (vs *VoltService) GetCircuitID() []byte {
1459 return []byte(vs.CircuitID)
1460}
1461
1462// GetRemoteID to get remote id
1463func (vs *VoltService) GetRemoteID() []byte {
1464 return []byte(vs.RemoteID)
1465}
1466
1467// IPAssigned to check if ip is assigned
1468func (vs *VoltService) IPAssigned() bool {
1469 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1470 return true
1471 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1472 return true
1473 }
1474 return false
1475}
1476
1477// GetServiceNameFromCookie to get service name from cookie
1478func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
1479
1480 var vlan uint64
1481 vlanControl := (tableMetadata >> 32) & 0xF
1482
1483 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1484 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1485 vlan = (tableMetadata >> 16) & 0xFFFF
1486 } else {
1487 //Fetching CVlan for other vlanControl
1488 vlan = cookie >> 52
1489 }
1490 logger.Infow(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
1491 var vlans []of.VlanType
1492 vlans = append(vlans, of.VlanType(vlan))
1493 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1494 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301495 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301496 } else {
1497 logger.Errorw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
1498 }
1499 return service
1500}
1501
1502//MigrateServicesReqStatus - update vnet request status
1503type MigrateServicesReqStatus string
1504
1505const (
1506 //MigrateSrvsReqInit constant
1507 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
1508 //MigrateSrvsReqDeactTriggered constant
1509 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
1510 //MigrateSrvsReqCompleted constant
1511 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1512)
1513
1514//MigrateServicesRequest - update vnet request params
1515type MigrateServicesRequest struct {
1516 ID string
1517 OldVnetID string
1518 NewVnetID string
1519 ServicesList map[string]bool
1520 DeviceID string
1521 Status MigrateServicesReqStatus
1522 MigrateServicesLock sync.RWMutex
1523}
1524
1525func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
1526
1527 var msr MigrateServicesRequest
1528 msr.OldVnetID = oldVnetID
1529 msr.NewVnetID = newVnetID
1530 msr.ID = id
1531 msr.ServicesList = serviceMap
1532 msr.DeviceID = deviceID
1533 msr.Status = MigrateSrvsReqInit
1534 return &msr
1535}
1536
1537//GetMsrKey - generates migrate service request key
1538func (msr *MigrateServicesRequest) GetMsrKey() string {
1539 return msr.OldVnetID + "-" + msr.ID
1540}
1541
1542// //isRequestComplete - return if all request has been processed and completed
1543// // RequestProcessed indicates that all the profile de-activation has been triggered
1544// // And the associated profiles indicates the profiles awaiting results
1545// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1546// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1547// return (len(edr.AssociatedProfiles) == 0)
1548// }
1549
1550//WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301551func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301552 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)})
1553 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301554 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301555 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301556 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301557 }
1558 }
1559}
1560
1561//MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301562func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301563
1564 logger.Warnw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
1565 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
1566 return errors.New("Old Vnet Id not found")
1567 }
1568 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
1569 return errors.New("New Vnet Id not found")
1570 }
1571
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301572 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301573 if d == nil {
1574 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1575 return errorCodes.ErrDeviceNotFound
1576 }
1577
1578 serviceMap := make(map[string]bool)
1579
1580 for _, service := range serviceList {
1581 serviceMap[service] = false
1582 }
1583 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301584 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301585
1586 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301587 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301588 return nil
1589}
1590
1591//ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301592func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301593 va := GetApplication()
1594 for srv, processed := range msr.ServicesList {
1595
1596 //Indicates new service is already created and only deletion of old one is pending
1597 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301598 va.DelService(cntx, srv, true, nil, true)
1599 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301600 continue
1601 }
1602
1603 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1604 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1605 vs := vsIntf.(*VoltService)
1606 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1607 if vpv == nil {
1608 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
1609 continue
1610 }
1611 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1612 vpv.Blocked = true
1613
1614 // setDeactTrigger := func(key, value interface{}) bool {
1615 // vs := value.(*VoltService)
1616 vs.ServiceLock.Lock()
1617 vs.UpdateInProgress = true
1618 metadata := &MigrateServiceMetadata{
1619 NewVnetID: msr.NewVnetID,
1620 RequestID: msr.ID,
1621 }
1622 vs.Metadata = metadata
1623 vs.ServiceLock.Unlock()
1624
1625 //vpv flows will be removed when last service is removed from it and
1626 // new vpv flows will be installed when new service is added
1627 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301628 vpv.DelTrapFlows(cntx)
1629 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301630 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301631 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301632 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301633 }
1634 } else {
1635 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1636 }
1637 }
1638}
1639
1640//AddMigratingServices - store msr info to device obj
1641func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
1642
1643 var msrMap *util.ConcurrentMap
1644 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1645 msrMap = util.NewConcurrentMap()
1646 } else {
1647 msrMap = msrMapIntf.(*util.ConcurrentMap)
1648 }
1649
1650 msrMap.Set(msr.ID, msr)
1651 logger.Infow(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
1652
1653 d.MigratingServices.Set(msr.OldVnetID, msrMap)
1654 logger.Infow(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
1655
1656}
1657
1658//getMigrateServicesRequest - fetches msr info from device
1659func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
1660 if vd := va.GetDevice(deviceID); vd != nil {
1661 logger.Infow(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
1662 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1663 msrList := msrListIntf.(*util.ConcurrentMap)
1664 logger.Infow(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
1665 if msrObj, ok := msrList.Get(requestID); ok {
1666 return msrObj.(*MigrateServicesRequest)
1667 }
1668
1669 }
1670 }
1671 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
1672 return nil
1673}
1674
1675//updateMigrateServicesRequest - Updates the device with updated msr
1676func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
1677 if vd := va.GetDevice(deviceID); vd != nil {
1678 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1679 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1680 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1681 }
1682 }
1683 }
1684}
1685
1686//updateVnetProfile - Called on flow process completion
1687// Removes old service and creates new VPV & service with udpated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301688func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301689
Tinoj Joseph1d108322022-07-13 10:07:39 +05301690 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 +05301691
1692 nvs := VoltService{}
1693 nvs.VoltServiceCfg = vs.VoltServiceCfg
1694 nvs.Device = vs.Device
1695 nvs.Ipv4Addr = vs.Ipv4Addr
1696 nvs.Ipv6Addr = vs.Ipv6Addr
1697 nvs.UsMeterID = vs.UsMeterID
1698 nvs.DsMeterID = vs.DsMeterID
1699 nvs.AggDsMeterID = vs.AggDsMeterID
1700 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1701 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1702 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1703 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1704 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1705 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1706 nvs.PendingFlows = vs.PendingFlows
1707 nvs.AssociatedFlows = vs.AssociatedFlows
1708 nvs.DeleteInProgress = vs.DeleteInProgress
1709 nvs.ForceDelete = vs.ForceDelete
1710 nvs.BwAvailInfo = vs.BwAvailInfo
1711 nvs.UpdateInProgress = vs.UpdateInProgress
1712
1713 if nvs.DeleteInProgress {
1714 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1715 return
1716 }
1717
1718 metadata := vs.Metadata.(*MigrateServiceMetadata)
1719 oldVnetID := vs.VnetID
1720 nvs.VnetID = metadata.NewVnetID
1721 id := metadata.RequestID
1722 oldSrvName := vs.Name
1723
1724 if metadata == nil || metadata.NewVnetID == "" {
1725 logger.Errorw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
1726 return
1727 }
1728
1729 //First add the new service and then only delete the old service
1730 // Since if post del service in case of pod crash or reboot, the service data will be lost
1731 va := GetApplication()
1732 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1733 vnets := strings.Split(metadata.NewVnetID, "-")
1734 svlan, _ := strconv.Atoi(vnets[0])
1735 nvs.SVlan = of.VlanType(svlan)
1736 nvs.UpdateInProgress = false
1737 nvs.Metadata = nil
1738 nvs.Trigger = ServiceVlanUpdate
1739
1740 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1741 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1742 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1743
1744 //TODO:Nav Pass a copy, not the pointer
1745 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 +05301746 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301747 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1748 }
1749 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1750
1751 msr.ServicesList[oldSrvName] = true
1752 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301753 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301754
1755 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 +05301756 va.DelService(cntx, oldSrvName, true, nil, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301757 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 +05301758 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301759}
1760
1761//serviceMigrated - called on successful service updation
1762// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301763func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301764
1765 msr.MigrateServicesLock.Lock()
1766 defer msr.MigrateServicesLock.Unlock()
1767
1768 delete(msr.ServicesList, serviceName)
1769
1770 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301771 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301772 return
1773 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301774 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301775 //TODO:Nav - Need for any Response to SubMgr?
1776}
1777
1778//TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301779func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1780 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301781}
1782
1783//FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301784func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301785
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301786 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301787 for _, msr := range msrList {
1788 b, ok := msr.Value.([]byte)
1789 if !ok {
1790 logger.Warn(ctx, "The value type is not []byte")
1791 continue
1792 }
1793 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301794 msrAction(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301795 logger.Warnw(ctx, "Triggering Pending Migrate Services Req", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID, "Device": device, "PendingProfiles": len(msr.ServicesList)})
1796
1797 }
1798}
1799
1800// createMigrateServicesFromString to create Service from string
1801func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
1802 var msr MigrateServicesRequest
1803 if err := json.Unmarshal(b, &msr); err == nil {
1804 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
1805
1806 } else {
1807 logger.Warn(ctx, "Unmarshal failed")
1808 }
1809 return &msr
1810}
1811
1812//storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301813func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301814 d := GetApplication().GetDevice(msr.DeviceID)
1815 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301816 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301817}
1818
1819//forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301820func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301821 for srv := range msr.ServicesList {
1822 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301823 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301824 }
1825 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301826 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301827}
1828
1829//DeepEqualServicecfg - checks if the given service cfgs are same
1830func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1831 if nvs.Name != evs.Name {
1832 return false
1833 }
1834 if nvs.UniVlan != evs.UniVlan {
1835 return false
1836 }
1837 if nvs.CVlan != evs.CVlan {
1838 return false
1839 }
1840 if nvs.SVlan != evs.SVlan {
1841 return false
1842 }
1843 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1844 return false
1845 }
1846 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1847 return false
1848 }
1849 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1850 return false
1851 }
1852 if nvs.TechProfileID != evs.TechProfileID {
1853 return false
1854 }
1855 if nvs.CircuitID != evs.CircuitID {
1856 return false
1857 }
1858 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1859 return false
1860 }
1861 if nvs.Port != evs.Port {
1862 return false
1863 }
1864 if nvs.PonPort != evs.PonPort {
1865 return false
1866 }
1867 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1868 return false
1869 }
1870 if nvs.IsOption82Disabled != evs.IsOption82Disabled {
1871 return false
1872 }
1873 if nvs.IgmpEnabled != evs.IgmpEnabled {
1874 return false
1875 }
1876 if nvs.McastService != evs.McastService {
1877 return false
1878 }
1879 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1880 return false
1881 }
1882 if nvs.UsMeterProfile != evs.UsMeterProfile {
1883 return false
1884 }
1885 if nvs.DsMeterProfile != evs.DsMeterProfile {
1886 return false
1887 }
1888 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
1889 return false
1890 }
1891 if nvs.VnetID != evs.VnetID {
1892 return false
1893 }
1894 if nvs.MvlanProfileName != evs.MvlanProfileName {
1895 return false
1896 }
1897 if nvs.RemoteIDType != evs.RemoteIDType {
1898 return false
1899 }
1900 if nvs.SchedID != evs.SchedID {
1901 return false
1902 }
1903 if nvs.AllowTransparent != evs.AllowTransparent {
1904 return false
1905 }
1906 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
1907 return false
1908 }
1909 if nvs.DataRateAttr != evs.DataRateAttr {
1910 return false
1911 }
1912 if nvs.MinDataRateUs != evs.MinDataRateUs {
1913 return false
1914 }
1915 if nvs.MinDataRateDs != evs.MinDataRateDs {
1916 return false
1917 }
1918 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
1919 return false
1920 }
1921 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
1922 return false
1923 }
1924
1925 return true
1926}
1927
1928//TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301929func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301930
1931 //Clear the Flows flag if already set
1932 //This case happens only in case of some race condition
1933 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301934 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301935 logger.Errorw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1936 }
1937 }
1938
1939 if vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301940 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301941 logger.Errorw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1942 }
1943 }
1944
1945 vs.ServiceLock.Lock()
1946 cookieList := []uint64{}
1947 for cookie := range vs.AssociatedFlows {
1948 cookieList = append(cookieList, convertToUInt64(cookie))
1949 }
1950 vs.ServiceLock.Unlock()
1951
1952 if len(cookieList) == 0 {
1953 return false
1954 }
1955
1956 //Trigger Flow Delete
1957 for _, cookie := range cookieList {
1958 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
1959 flow := &of.VoltFlow{}
1960 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1961 subFlow := of.NewVoltSubFlow()
1962 subFlow.Cookie = cookie
1963 flow.SubFlows[cookie] = subFlow
1964 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301965 if err := vs.DelFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301966 logger.Errorw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
1967 }
1968 }
1969 }
1970 return true
1971}
1972
1973//triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
1974func (vs *VoltService) triggerServiceInProgressInd() {
1975}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301976
1977// JsonMarshal wrapper function for json Marshal VoltService
1978func (vs *VoltService) JsonMarshal() ([]byte, error) {
1979 return json.Marshal(VoltService{
1980 VoltServiceCfg: vs.VoltServiceCfg,
1981 VoltServiceOper: VoltServiceOper{
1982 Device: vs.VoltServiceOper.Device,
1983 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
1984 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
1985 UsMeterID: vs.VoltServiceOper.UsMeterID,
1986 DsMeterID: vs.VoltServiceOper.DsMeterID,
1987 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
1988 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
1989 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
1990 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
1991 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
1992 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
1993 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
1994 PendingFlows: vs.VoltServiceOper.PendingFlows,
1995 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
1996 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
1997 ForceDelete: vs.VoltServiceOper.ForceDelete,
1998 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
1999 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2000 Metadata: vs.VoltServiceOper.Metadata,
2001 },
2002 })
2003}
Tinoj Josephec742f62022-09-29 19:11:10 +05302004
2005// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302006func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302007 var svcList []*VoltService
2008 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2009 va.ServiceByName.Range(func(key, value interface{}) bool {
2010 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302011 if len(deviceID) > 0 {
2012 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302013 if deviceID == vs.Device && portNo == vs.Port {
2014 svcList = append(svcList, vs)
2015 }
2016 } else {
2017 if deviceID == vs.Device {
2018 svcList = append(svcList, vs)
2019 }
2020 }
2021 } else {
2022 svcList = append(svcList, vs)
2023 }
2024 return true
2025 })
2026 return svcList, nil
2027}
2028
2029// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302030func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302031 logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302032 device, err := va.GetDeviceFromPort(portNo)
2033 if err != nil {
2034 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2035 return errorCodes.ErrPortNotFound
2036 }
2037 // If device id is not provided check only port number
2038 if deviceID == DeviceAny {
2039 deviceID = device.Name
2040 } else if deviceID != device.Name {
2041 logger.Errorw(ctx, "Wrong Device ID", log.Fields{"Device": deviceID, "Port": portNo})
2042 return errorCodes.ErrDeviceNotFound
2043 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302044 va.ServiceByName.Range(func(key, value interface{}) bool {
2045 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302046 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302047 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302048 logger.Infow(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302049 return true
2050 }
2051 if portNo == vs.Port && !vs.IsActivated {
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302052 p := device.GetPort(vs.Port)
Tinoj Josephec742f62022-09-29 19:11:10 +05302053 if p == nil {
2054 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2055 return true
2056 }
2057 logger.Infow(ctx, "Service Activate", log.Fields{"Name": vs.Name})
2058 vs.IsActivated = true
2059 va.ServiceByName.Store(vs.Name, vs)
2060 vs.WriteToDb(cntx)
2061 // If port is already up send indication to vpv
2062 if p.State == PortStateUp {
2063 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2064 // PortUp call initiates flow addition
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302065 vpv.PortUpInd(cntx, device, portNo)
Tinoj Josephec742f62022-09-29 19:11:10 +05302066 } else {
2067 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2068 }
2069 }
2070 }
2071 return true
2072 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302073 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302074}
2075
2076// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302077func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302078 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2079 va.ServiceByName.Range(func(key, value interface{}) bool {
2080 vs := value.(*VoltService)
2081 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302082 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2083 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
2084 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 +05302085 return true
2086 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302087 if portNo == vs.Port && vs.IsActivated {
Tinoj Josephec742f62022-09-29 19:11:10 +05302088 vs.IsActivated = false
2089 va.ServiceByName.Store(vs.Name, vs)
2090 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302091 device, err := va.GetDeviceFromPort(portNo)
2092 if err != nil {
2093 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2094 // So no error is returned
2095 logger.Infow(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2096 return true
2097 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302098 p := device.GetPort(vs.Port)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302099 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable){
Tinoj Josephec742f62022-09-29 19:11:10 +05302100 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2101 // Port down call internally deletes all the flows
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302102 vpv.PortDownInd(cntx, deviceID, portNo, true)
Tinoj Josephec742f62022-09-29 19:11:10 +05302103 if vpv.IgmpEnabled {
2104 va.ReceiverDownInd(cntx, deviceID, portNo)
2105 }
2106 } else {
2107 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2108 }
2109 }
2110 }
2111 return true
2112 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302113 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302114}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302115
Tinoj Josephec742f62022-09-29 19:11:10 +05302116/* GetServicePbit to get first set bit in the pbit map
2117 returns -1 : If configured to match on all pbits
2118 returns 8 : If no pbits are configured
2119 returns first pbit if specific pbit is configured */
2120func (vs *VoltService) GetServicePbit() int {
2121 if vs.IsPbitExist(of.PbitMatchAll) {
2122 return -1
2123 }
2124 for pbit:= 0; pbit < int(of.PbitMatchNone); pbit++ {
2125 if vs.IsPbitExist(of.PbitType(pbit)) {
2126 return pbit
2127 }
2128 }
2129 return int(of.PbitMatchNone)
2130}