blob: 4ddd45d74e142e303e0f5e764fbe73cc57ab11b4 [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
74 DsRemarkPbitsMap map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
75 TechProfileID uint16
76 CircuitID string
77 RemoteID []byte
78 Port string
79 PonPort uint32
80 MacLearning MacLearningType
81 IsOption82Disabled bool
82 IgmpEnabled bool
83 McastService bool
84 ONTEtherTypeClassification int
85 VlanControl VlanControl
86 UsMeterProfile string
87 DsMeterProfile string
88 AggDsMeterProfile string
89 VnetID string
90 MvlanProfileName string
91 RemoteIDType string
92 SchedID int
93 AllowTransparent bool
94 EnableMulticastKPI bool
95 DataRateAttr string
96 MinDataRateUs uint32
97 MinDataRateDs uint32
98 MaxDataRateUs uint32
99 MaxDataRateDs uint32
Tinoj Josephec742f62022-09-29 19:11:10 +0530100 IsActivated bool
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +0530101 Trigger ServiceTrigger
Naveen Sampath04696f72022-06-13 15:19:14 +0530102}
103
104// VoltServiceOper structure
105type VoltServiceOper struct {
106 //MacLearning bool
107 //MacAddr net.HardwareAddr
108 Device string
109 Ipv4Addr net.IP
110 Ipv6Addr net.IP
111
112 UsMeterID uint32
113 DsMeterID uint32
114 AggDsMeterID uint32
115
116 //Multiservice-Fix
117 UsHSIAFlowsApplied bool
118 DsHSIAFlowsApplied bool
119 UsDhcpFlowsApplied bool
120 DsDhcpFlowsApplied bool
121 IgmpFlowsApplied bool
122 Icmpv6FlowsApplied bool
123
124 ServiceLock sync.RWMutex `json:"-"`
125 PendingFlows map[string]bool
126 AssociatedFlows map[string]bool
127 DeleteInProgress bool
128 ForceDelete bool
129 BwAvailInfo string
130
131 UpdateInProgress bool
132 Metadata interface{}
133}
134
135// VoltService structure
136type VoltService struct {
137 VoltServiceCfg
138 VoltServiceOper
139 Version string
140}
141
142//ServiceTrigger - Service activation trigger
143type ServiceTrigger int
144
145const (
146 //NBActivate - Service added due to NB Action
147 NBActivate ServiceTrigger = 0
148 //ServiceVlanUpdate - Service added due to Svlan Update
149 ServiceVlanUpdate ServiceTrigger = 1
150)
151
152// AppMutexes structure
153type AppMutexes struct {
154 ServiceDataMutex sync.Mutex `json:"-"`
155 VnetMutex sync.Mutex `json:"-"`
156}
157
158//MigrateServiceMetadata - migrate services request metadata
159type MigrateServiceMetadata struct {
160 NewVnetID string
161 RequestID string
162}
163
164// AppMutex variable
165var AppMutex AppMutexes
166
167// NewVoltService for constructor for volt service
168func NewVoltService(cfg *VoltServiceCfg) *VoltService {
169 var vs VoltService
170 vs.VoltServiceCfg = *cfg
171 vs.UsHSIAFlowsApplied = false
172 vs.DsHSIAFlowsApplied = false
173 vs.DeleteInProgress = false
174 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
175
176 vs.MacAddr = cfg.MacAddr
177 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
178 vs.Ipv6Addr = net.ParseIP("::")
179 vs.PendingFlows = make(map[string]bool)
180 vs.AssociatedFlows = make(map[string]bool)
181 return &vs
182}
183
184// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530185func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530186
187 vs.ServiceLock.RLock()
188 defer vs.ServiceLock.RUnlock()
189
190 if vs.DeleteInProgress {
191 logger.Warnw(ctx, "Skipping Redis Update for Service, Service delete in progress", log.Fields{"Service": vs.Name})
192 return
193 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530194 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530195}
196
197//ForceWriteToDb force commit a service to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530198func (vs *VoltService) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530199 b, err := json.Marshal(vs)
200
201 if err != nil {
202 logger.Errorw(ctx, "Json Marshal Failed for Service", log.Fields{"Service": vs.Name})
203 return
204 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530205 if err1 := db.PutService(cntx, vs.Name, string(b)); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530206 logger.Errorw(ctx, "DB write oper failed for Service", log.Fields{"Service": vs.Name})
207 }
208}
209
210// isDataRateAttrPresent to check if data attribute is present
211func (vs *VoltService) isDataRateAttrPresent() bool {
212 return vs.DataRateAttr == DSLAttrEnabled
213}
214
215// DelFromDb delete a service from DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530216func (vs *VoltService) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530217 logger.Debugw(ctx, "Deleting Service from DB", log.Fields{"Name": vs.Name})
218 //TODO - Need to understand and delete the second call
219 //Calling twice has worked though don't know why
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530220 _ = db.DelService(cntx, vs.Name)
221 _ = db.DelService(cntx, vs.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530222}
223
224// MatchesVlans find the service that matches the VLANs. In this case it is
225// purely based on CVLAN. The CVLAN can sufficiently be used to
226// match a service
227func (vs *VoltService) MatchesVlans(vlans []of.VlanType) bool {
228 if len(vlans) != 1 {
229 return false
230 }
231
232 if vlans[0] == vs.CVlan {
233 return true
234 }
235 return false
236}
237
238// MatchesPbits allows matching a service to a pbit. This is used
239// to search for a service matching the pbits, typically to identify
240// attributes for other flows such as DHCP, IGMP, etc.
241func (vs *VoltService) MatchesPbits(pbits []of.PbitType) bool {
242 for _, pbit := range pbits {
243 for _, pb := range vs.Pbits {
244 if pb == pbit {
245 return true
246 }
247 }
248 }
249 return false
250}
251
252// IsPbitExist allows matching a service to a pbit. This is used
253// to search for a service matching the pbit
254func (vs *VoltService) IsPbitExist(pbit of.PbitType) bool {
255 for _, pb := range vs.Pbits {
256 if pb == pbit {
257 return true
258 }
259 }
260 return false
261}
262
263// AddHsiaFlows - Adds US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530264func (vs *VoltService) AddHsiaFlows(cntx context.Context) {
265 if err := vs.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530266 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
267 vs.triggerServiceFailureInd(statusCode, statusMessage)
268 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530269 if err := vs.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530270 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
271 vs.triggerServiceFailureInd(statusCode, statusMessage)
272 }
273}
274
275//DelHsiaFlows - Deletes US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530276func (vs *VoltService) DelHsiaFlows(cntx context.Context) {
277 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530278 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
279 vs.triggerServiceFailureInd(statusCode, statusMessage)
280 }
281
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530282 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530283 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
284 vs.triggerServiceFailureInd(statusCode, statusMessage)
285 }
286}
287
288// AddUsHsiaFlows - Add US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530289func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530290
291 if vs.DeleteInProgress || vs.UpdateInProgress {
292 logger.Errorw(ctx, "Ignoring US HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
293 return nil
294 }
295
296 va := GetApplication()
297 logger.Infow(ctx, "Configuring US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
298 if !vs.UsHSIAFlowsApplied || vgcRebooted {
299 device, err := va.GetDeviceFromPort(vs.Port)
300 if err != nil {
301 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
302 return errorCodes.ErrDeviceNotFound
303 } else if device.State != controller.DeviceStateUP {
304 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
305 return nil
306 }
307
308 vs.Device = device.Name
309 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
310 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
311
312 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
313 pBits := vs.Pbits
314
315 //If no pbits configured for service, hence add PbitNone for flows
316 if len(vs.Pbits) == 0 {
317 pBits = append(pBits, PbitMatchNone)
318 }
319 for _, pbits := range pBits {
320 usflows, err := vs.BuildUsHsiaFlows(pbits)
321 if err != nil {
322 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
323 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
324 vs.triggerServiceFailureInd(statusCode, statusMessage)
325 continue
326 }
327 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530328 if err := vs.AddFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530329 logger.Errorw(ctx, "Error adding HSIA US flows", log.Fields{"Reason": err.Error()})
330 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
331 vs.triggerServiceFailureInd(statusCode, statusMessage)
332 }
333 }
334 vs.UsHSIAFlowsApplied = true
335 logger.Infow(ctx, "Pushed US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
336 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530337 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530338 return nil
339}
340
341// AddDsHsiaFlows - Add DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530342func (vs *VoltService) AddDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530343 if vs.DeleteInProgress {
344 logger.Errorw(ctx, "Ignoring DS HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
345 return nil
346 }
347
348 va := GetApplication()
349 logger.Infow(ctx, "Configuring DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
350 if !vs.DsHSIAFlowsApplied || vgcRebooted {
351 device, err := va.GetDeviceFromPort(vs.Port)
352 if err != nil {
353 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
354 return errorCodes.ErrDeviceNotFound
355 } else if device.State != controller.DeviceStateUP {
356 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
357 return nil
358 }
359
360 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
361 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
362
363 //If no pbits configured for service, hence add PbitNone for flows
364 if len(vs.DsRemarkPbitsMap) == 0 {
365 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
366 if err != nil {
367 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
368 return err
369 }
370 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530371 if err = vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530372 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
373 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
374 vs.triggerServiceFailureInd(statusCode, statusMessage)
375 }
376 } else {
377 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
378 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
379 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
380 if err != nil {
381 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
382 return err
383 }
384 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
385 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530386 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530387 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
388 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
389 vs.triggerServiceFailureInd(statusCode, statusMessage)
390 }
391 } else {
392 for matchPbit := range vs.DsRemarkPbitsMap {
393 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
394 if err != nil {
395 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
396 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
397 vs.triggerServiceFailureInd(statusCode, statusMessage)
398 continue
399 }
400 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530401 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530402 logger.Errorw(ctx, "Failed to Add HSIA DS flows", log.Fields{"Reason": err})
403 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
404 vs.triggerServiceFailureInd(statusCode, statusMessage)
405 }
406 }
407 }
408 }
409 vs.DsHSIAFlowsApplied = true
410 logger.Infow(ctx, "Pushed DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
411 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530412 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530413 return nil
414}
415
416// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530417func (vs *VoltService) DelUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530418
419 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Services": vs.Name})
420 if vs.UsHSIAFlowsApplied || vgcRebooted {
421 device, err := GetApplication().GetDeviceFromPort(vs.Port)
422 if err != nil {
423 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
424 return errorCodes.ErrDeviceNotFound
425 }
426
427 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
428 pBits := vs.Pbits
429
430 //If no pbits configured for service, hence add PbitNone for flows
431 if len(vs.Pbits) == 0 {
432 pBits = append(pBits, PbitMatchNone)
433 }
434 for _, pbits := range pBits {
435 usflows, err := vs.BuildUsHsiaFlows(pbits)
436 if err != nil {
437 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
438 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
439 vs.triggerServiceFailureInd(statusCode, statusMessage)
440 continue
441 }
442 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530443 if err = vs.DelFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530444 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
445 vs.triggerServiceFailureInd(statusCode, statusMessage)
446 }
447 }
448 vs.UsHSIAFlowsApplied = false
449 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530450 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530451 return nil
452}
453
454// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530455func (vs *VoltService) DelDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530456
457 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Services": vs.Name})
458 if vs.DsHSIAFlowsApplied || vgcRebooted {
459 device, err := GetApplication().GetDeviceFromPort(vs.Port)
460 if err != nil {
461 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
462 return errorCodes.ErrDeviceNotFound
463 }
464
465 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
466 var matchPbit int
467 //If no pbits configured for service, hence add PbitNone for flows
468 if len(vs.DsRemarkPbitsMap) == 0 {
469 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
470 if err != nil {
471 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
472 return err
473 }
474 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530475 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530476 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
477 vs.triggerServiceFailureInd(statusCode, statusMessage)
478 }
479 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
480 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
481 if err != nil {
482 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
483 return err
484 }
485 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530486 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530487 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
488 vs.triggerServiceFailureInd(statusCode, statusMessage)
489 }
490 } else {
491 for matchPbit = range vs.DsRemarkPbitsMap {
492 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
493 if err != nil {
494 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
495 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
496 vs.triggerServiceFailureInd(statusCode, statusMessage)
497 continue
498 }
499 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530500 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530501 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
502 vs.triggerServiceFailureInd(statusCode, statusMessage)
503 }
504 }
505 }
506 vs.DsHSIAFlowsApplied = false
507 }
508 logger.Infow(ctx, "Deleted HSIA DS flows from DB successfuly", log.Fields{"ServiceName": vs.Name})
509 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530510 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530511 return nil
512}
513
514// BuildDsHsiaFlows build the DS HSIA flows
515// Called for add/delete HSIA flows
516func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
517 flow := &of.VoltFlow{}
518 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
519
520 // Get the out and in ports for the flows
521 device, err := GetApplication().GetDeviceFromPort(vs.Port)
522 if err != nil {
523 return nil, errorCodes.ErrDeviceNotFound
524 }
525 inport, _ := GetApplication().GetPortID(device.NniPort)
526 outport, _ := GetApplication().GetPortID(vs.Port)
527 // PortName and PortID to be used for validation of port before flow pushing
528 flow.PortID = outport
529 flow.PortName = vs.Port
530 allowTransparent := 0
531 if vs.AllowTransparent {
532 allowTransparent = 1
533 }
534
535 // initialized actnPbit to 0 for cookie genration backward compatibility.
536 var actnPbit of.PbitType
537 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
538
539 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
540 //| 12-bit cvlan/UniVlan | 4 bits action pbit | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
541 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
542 cookie = cookie | of.DsFlowMask
543 cookie = cookie + (valToShift << 4) + uint64(pbits)
544 return cookie
545 }
546
547 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
548 if err != nil {
549 logger.Errorw(ctx, "DS HSIA flow push failed: Invalid SvlanTpid", log.Fields{"SvlanTpid": vs.SVlanTpid, "Service": vs.Name})
550 return nil, err
551 }
552
553 // Add Table-0 flow that deals with the outer VLAN in pOLT
554 {
555 subflow1 := of.NewVoltSubFlow()
556 subflow1.SetTableID(0)
557 subflow1.SetGoToTable(1)
558 subflow1.SetInPort(inport)
559
560 if pbits != PbitMatchNone {
561 subflow1.SetMatchPbit(pbits)
562 }
563
564 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
565 subflow1.SetPcp(of.PbitType(remarkPbit))
566 // match & action pbits are different, set remark-pbit action
567 actnPbit = of.PbitType(remarkPbit)
568 // mask remark p-bit to 4bits
569 actnPbit = actnPbit & 0x0F
570 }
571
572 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
573 return nil, err
574 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530575 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530576 if NonZeroMacAddress(vs.MacAddr) {
577 subflow1.SetMatchDstMac(vs.MacAddr)
578 }
579 subflow1.Priority = of.HsiaFlowPriority
580 subflow1.SetMeterID(vs.DsMeterID)
581
582 /* WriteMetaData 8 Byte(uint64) usage:
583 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
584 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
585 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
586 subflow1.SetWriteMetadata(metadata)
587
588 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
589 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
590 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
591 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
592
593 //TODO-COMM:
594 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
595 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
596 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
597 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
598
599 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
600 subflow1.SetTableMetadata(metadata)
601 // TODO - We are using cookie as key and must come up with better cookie
602 // allocation algorithm
603 /**
604 * Cokies may clash when -
605 * on same uni-port we have two sub-service
606 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
607 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
608 * However, this p-bit re-use will not be allowed by sub-mgr.
609 */
610 if vs.VlanControl == OLTCVlanOLTSVlan {
611 /**
612 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
613 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
614 * use old cookie.
615 */
616 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
617 if vgcRebooted {
618 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
619 }
620 } else {
621 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
622 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
623 }
624
625 flow.SubFlows[subflow1.Cookie] = subflow1
626 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
627 "subflow": subflow1})
628 }
629
630 //Add Table-1 flow that deals with inner VLAN at the ONU
631 {
632 subflow2 := of.NewVoltSubFlow()
633 subflow2.SetTableID(1)
634 subflow2.SetInPort(inport)
635 if NonZeroMacAddress(vs.MacAddr) {
636 subflow2.SetMatchDstMac(vs.MacAddr)
637 }
638
639 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
640 return nil, err
641 }
642 if pbits != PbitMatchNone {
643 subflow2.SetMatchPbit(pbits)
644 }
645
646 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
647 subflow2.SetPcp(of.PbitType(remarkPbit))
648 }
649
650 subflow2.SetOutPort(outport)
651 subflow2.SetMeterID(vs.DsMeterID)
652
653 // refer Table-0 flow generation for byte information
654 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
655 subflow2.SetWriteMetadata(metadata)
656
657 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
658 if util.IsNniPort(inport) {
659 metadata = uint64(outport)
660 } else {
661 // refer Table-0 flow generation for byte information
662 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
663 }
664 subflow2.SetTableMetadata(metadata)
665 // Setting of Cookie - TODO - Improve the allocation algorithm
666 if vs.VlanControl == OLTCVlanOLTSVlan {
667 /**
668 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
669 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
670 * use old cookie.
671 */
672 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
673 if vgcRebooted {
674 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
675 }
676 } else {
677 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
678 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
679 }
680
681 subflow2.Priority = of.HsiaFlowPriority
682 flow.SubFlows[subflow2.Cookie] = subflow2
683 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
684 "subflow": subflow2})
685 }
686
687 return flow, nil
688}
689
690// BuildUsHsiaFlows build the US HSIA flows
691// Called for add/delete HSIA flows
692func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
693 flow := &of.VoltFlow{}
694 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
695
696 // Get the out and in ports for the flows
697 device, err := GetApplication().GetDeviceFromPort(vs.Port)
698 if err != nil {
699 return nil, errorCodes.ErrDeviceNotFound
700 }
701 outport, _ := GetApplication().GetPortID(device.NniPort)
702 inport, _ := GetApplication().GetPortID(vs.Port)
703 // PortName and PortID to be used for validation of port before flow pushing
704 flow.PortID = inport
705 flow.PortName = vs.Port
706 allowTransparent := 0
707 reqBwInfo := 0
708 if vs.AllowTransparent {
709 allowTransparent = 1
710 }
711 if vs.BwAvailInfo == "" {
712 reqBwInfo = 1
713 }
714
715 // Add Table-0 flow that deals with the inner VLAN in ONU
716 {
717 subflow1 := of.NewVoltSubFlow()
718 subflow1.SetTableID(0)
719 subflow1.SetGoToTable(1)
720 subflow1.SetInPort(inport)
721
Naveen Sampath04696f72022-06-13 15:19:14 +0530722 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
723 return nil, err
724 }
725 subflow1.SetMeterID(vs.UsMeterID)
726
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +0530727 if GetApplication().GetVendorID() == Radisys {
728 if pbits != PbitMatchNone {
729 subflow1.SetMatchPbit(pbits)
730 }
731 /* WriteMetaData 8 Byte(uint64) usage:
732 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
733 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
734 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
735 subflow1.SetWriteMetadata(metadata)
736 /* TableMetaData 8 Byte(uint64) usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
737 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
738 | 000 | 0 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
739 | reserved | reqBwInfo | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
740 metadata = uint64(reqBwInfo)<<60 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +0530741
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +0530742 // // In case of MAC Learning enabled voltha will buffer the US flow installation.
743 // if NonZeroMacAddress(vs.MacAddr) {
744 // subflow1.SetMatchSrcMac(vs.MacAddr)
745 // } else if vs.MacLearning != MacLearning {
746 // metadata |= 1 << 57
747 // logger.Infow(ctx, "Buffer us flow at adapter", log.Fields{"metadata": metadata})
748 // }
749 subflow1.SetTableMetadata(metadata)
750 } else {
751 /* WriteMetaData 8 Byte(uint64) usage:
752 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
753 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
754 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
755 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
756 subflow1.SetWriteMetadata(metadata)
757 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530758 if vs.VlanControl == OLTCVlanOLTSVlan {
759 /**
760 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
761 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
762 * use old cookie.
763 */
764 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
765 if vgcRebooted {
766 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
767 }
768 } else {
769 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
770 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
771 }
772 subflow1.Priority = of.HsiaFlowPriority
773 flow.SubFlows[subflow1.Cookie] = subflow1
774 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
775 }
776
777 //Add Table-1 flow that deals with the outer vlan in pOLT
778 {
779 subflow2 := of.NewVoltSubFlow()
780 subflow2.SetTableID(1)
781 subflow2.SetInPort(inport)
782
Naveen Sampath04696f72022-06-13 15:19:14 +0530783 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
784 return nil, err
785 }
786 subflow2.SetInPort(inport)
787 subflow2.SetOutPort(outport)
788 subflow2.SetMeterID(vs.UsMeterID)
789
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +0530790 if GetApplication().GetVendorID() == Radisys {
791 if pbits != PbitMatchNone {
792 subflow2.SetMatchPbit(pbits)
793 }
794 // refer Table-0 flow generation for byte information
795 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
796 subflow2.SetWriteMetadata(metadata)
797 // refer Table-0 flow generation for byte information
798 metadata = uint64(reqBwInfo)<<60 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
799 // // In case of MAC Learning enabled voltha will buffer the US flow installation.
800 // if NonZeroMacAddress(vs.MacAddr) {
801 // subflow2.SetMatchSrcMac(vs.MacAddr)
802 // } else if vs.MacLearning != MacLearningNone {
803 // metadata |= 1 << 57
804 // logger.Infow(ctx, "Buffer us flow at adapter", log.Fields{"metadata": metadata})
805 // }
806 subflow2.SetTableMetadata(metadata)
807 } else {
808 // refer Table-0 flow generation for byte information
809 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
810 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530811
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +0530812 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530813 if vs.VlanControl == OLTCVlanOLTSVlan {
814 /**
815 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
816 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
817 * use old cookie.
818 */
819 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
820 if vgcRebooted {
821 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
822 }
823 } else {
824 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
825 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
826 }
827 subflow2.Priority = of.HsiaFlowPriority
828
829 flow.SubFlows[subflow2.Cookie] = subflow2
830 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
831 }
832
833 return flow, nil
834}
835
836func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
837 //| 12-bit cvlan/UniVlan | 4 bits empty | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
838 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
839 cookie = cookie | of.UsFlowMask
840 cookie = cookie + (valToShift << 4) + uint64(pbits)
841 return cookie
842}
843
844// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
845// based on different Vlan Controls
846func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
847 switch vs.VlanControl {
848 case None:
849 flow.SetMatchVlan(vs.SVlan)
850 case ONUCVlanOLTSVlan:
851 flow.SetMatchVlan(vs.CVlan)
852 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
853 case OLTCVlanOLTSVlan:
854 flow.SetMatchVlan(vs.UniVlan)
855 flow.SetSetVlan(vs.CVlan)
856 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
857 case ONUCVlan:
858 flow.SetMatchVlan(vs.SVlan)
859 case OLTSVlan:
860 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
861 flow.SetMatchVlan(vs.UniVlan)
862 flow.SetSetVlan(vs.SVlan)
863 } else if vs.UniVlan != of.VlanNone {
864 flow.SetMatchVlan(vs.UniVlan)
865 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
866 } else {
867 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
868 }
869 default:
870 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
871 return errorCodes.ErrInvalidParamInRequest
872 }
873 return nil
874}
875
876// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
877// based on different Vlan Controls
878func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
879 switch vs.VlanControl {
880 case None:
881 flow.SetMatchVlan(vs.SVlan)
882 case ONUCVlanOLTSVlan:
883 flow.SetMatchVlan(vs.SVlan)
884 flow.SetPopVlan()
885 case OLTCVlanOLTSVlan:
886 flow.SetMatchVlan(vs.SVlan)
887 flow.SetPopVlan()
888 flow.SetSetVlan(vs.UniVlan)
889 case ONUCVlan:
890 flow.SetMatchVlan(vs.SVlan)
891 case OLTSVlan:
892 flow.SetMatchVlan(vs.SVlan)
893 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
894 flow.SetSetVlan(vs.UniVlan)
895 } else {
896 flow.SetPopVlan()
897 }
898 default:
899 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
900 return errorCodes.ErrInvalidParamInRequest
901 }
902 return nil
903}
904
905// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
906// based on different Vlan Controls
907func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
908 switch vs.VlanControl {
909 case None:
910 flow.SetMatchVlan(vs.SVlan)
911 case ONUCVlanOLTSVlan:
912 if vs.UniVlan != of.VlanNone {
913 flow.SetMatchVlan(vs.UniVlan)
914 flow.SetSetVlan(vs.CVlan)
915 } else {
916 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
917 }
918 case OLTCVlanOLTSVlan:
919 flow.SetMatchVlan(vs.UniVlan)
920 case ONUCVlan:
921 if vs.UniVlan != of.VlanNone {
922 flow.SetMatchVlan(vs.UniVlan)
923 flow.SetSetVlan(vs.SVlan)
924 } else {
925 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
926 }
927 case OLTSVlan:
928 flow.SetMatchVlan(vs.UniVlan)
929 default:
930 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
931 return errorCodes.ErrInvalidParamInRequest
932 }
933 return nil
934}
935
936// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
937// based on different Vlan Controls
938func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
939 switch vs.VlanControl {
940 case None:
941 flow.SetMatchVlan(vs.SVlan)
942 case ONUCVlanOLTSVlan:
943 flow.SetMatchVlan(vs.CVlan)
944 if vs.UniVlan != of.VlanNone {
945 flow.SetSetVlan(vs.UniVlan)
946 } else {
947 flow.SetPopVlan()
948 }
949 case OLTCVlanOLTSVlan:
950 flow.SetMatchVlan(vs.UniVlan)
951 case ONUCVlan:
952 flow.SetMatchVlan(vs.SVlan)
953 if vs.UniVlan != of.VlanNone {
954 flow.SetSetVlan(vs.UniVlan)
955 } else {
956 flow.SetPopVlan()
957 }
958 case OLTSVlan:
959 flow.SetMatchVlan(vs.UniVlan)
960 default:
961 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
962 return errorCodes.ErrInvalidParamInRequest
963 }
964 return nil
965}
966
967// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530968func (vs *VoltService) SvcUpInd(cntx context.Context) {
969 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530970}
971
972// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530973func (vs *VoltService) SvcDownInd(cntx context.Context) {
974 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530975}
976
977// SetIpv4Addr to set ipv4 address
978func (vs *VoltService) SetIpv4Addr(addr net.IP) {
979 vs.Ipv4Addr = addr
980}
981
982// SetIpv6Addr to set ipv6 address
983func (vs *VoltService) SetIpv6Addr(addr net.IP) {
984 vs.Ipv6Addr = addr
985}
986
987// SetMacAddr to set mac address
988func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
989 vs.MacAddr = addr
990}
991
992// ----------------------------------------------
993// VOLT Application - Related to services
994// ---------------------------------------------
995// ---------------------------------------------------------------
996// Service CRUD functions. These are exposed to the overall binary
997// to be invoked from the point where the CRUD operations are received
998// from the external entities
999
1000// AddService : A service in the context of VOLT is a subscriber or service of a
1001// subscriber which is uniquely identified by a combination of MAC
1002// address, VLAN tags, 802.1p bits. However, in the context of the
1003// current implementation, a service is an entity that is identified by a
1004// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
1005// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301006func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301007 var mmUs, mmDs *VoltMeter
1008 var err error
1009
1010 //Take the Device lock only in case of NB add request.
1011 // Allow internal adds since internal add happen only under
1012 // 1. Restore Service from DB
1013 // 2. Service Migration
1014 if oper == nil {
1015 if svc := va.GetService(cfg.Name); svc != nil {
1016 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
1017 return errors.New("Service Already Exists")
1018 }
1019 }
1020
1021 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
1022 // Service doesn't exist. So create it and add to the port
1023 vs := NewVoltService(&cfg)
1024 if oper != nil {
1025 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1026 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1027 vs.Ipv4Addr = oper.Ipv4Addr
1028 vs.Ipv6Addr = oper.Ipv6Addr
1029 vs.MacLearning = cfg.MacLearning
1030 vs.PendingFlows = oper.PendingFlows
1031 vs.AssociatedFlows = oper.AssociatedFlows
1032 vs.DeleteInProgress = oper.DeleteInProgress
1033 vs.BwAvailInfo = oper.BwAvailInfo
1034 vs.Device = oper.Device
1035 } else {
1036
1037 //Sorting Pbit from highest
1038 sort.Slice(vs.Pbits, func(i, j int) bool {
1039 return vs.Pbits[i] > vs.Pbits[j]
1040 })
1041 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1042 }
1043 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1044
1045 // The bandwidth and shaper profile combined into meter
1046 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1047 vs.DsMeterID = mmDs.ID
1048 } else {
1049 return errors.New("DownStream meter profile not found")
1050 }
1051
1052 // The aggregated downstream meter profile
1053 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1054 // vs.AggDsMeterID = mmAg.ID
1055 // } else {
1056 // return errors.New("Aggregated meter profile not found")
1057 // }
1058
1059 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1060 // vs.UsMeterID = mmAg.ID
1061 // } else {
1062 // The bandwidth and shaper profile combined into meter
1063 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1064 vs.UsMeterID = mmUs.ID
1065 } else {
1066 return errors.New("Upstream meter profile not found")
1067 }
1068 //}
1069
1070 AppMutex.ServiceDataMutex.Lock()
1071 defer AppMutex.ServiceDataMutex.Unlock()
1072
1073 // Add the service to the VNET
1074 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1075 if vnet != nil {
1076 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1077 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301078 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301079 vpv.VpvLock.Unlock()
1080 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301081 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301082 }
1083 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301084 logger.Errorw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301085 return errors.New("VNET doesn't exist")
1086 }
1087
1088 vs.Version = database.PresentVersionMap[database.ServicePath]
1089 // Add the service to the volt application
1090 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301091 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301092
1093 if nil == oper {
1094
1095 if !vs.UsHSIAFlowsApplied {
1096 vs.triggerServiceInProgressInd()
1097 }
1098
1099 //Update meter profiles service count if service is being added from northbound
1100 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301101 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301102 if mmUs != nil {
1103 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301104 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301105 }
1106 //mmAg.AssociatedServices++
1107 //va.UpdateMeterProf(*mmAg)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301108 logger.Debugw(ctx, "northbound-service-add-sucessful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301109 }
1110
1111 logger.Warnw(ctx, "Added Service to DB", log.Fields{"Name": vs.Name, "Port": (vs.Port), "ML": vs.MacLearning})
1112 return nil
1113}
1114
1115//DelServiceWithPrefix - Deletes service with the provided prefix.
1116// Added for DT/TT usecase with sadis replica interface
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301117func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301118 va.ServiceByName.Range(func(key, value interface{}) bool {
1119 srvName := key.(string)
1120 vs := value.(*VoltService)
1121 if strings.Contains(srvName, prefix) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301122 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301123
1124 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1125 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1126 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1127
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301128 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301129 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1130 }
1131 }
1132 return true
1133 })
1134}
1135
1136// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301137func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301138
1139 AppMutex.ServiceDataMutex.Lock()
1140 defer AppMutex.ServiceDataMutex.Unlock()
1141
1142 logger.Warnw(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
1143 var noFlowsPresent bool
1144
1145 vsIntf, ok := va.ServiceByName.Load(name)
1146 if !ok {
1147 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1148 return
1149 }
1150 vs := vsIntf.(*VoltService)
1151 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1152 if vpv == nil {
1153 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
1154 return
1155 }
1156
1157 //Set this to avoid race-condition during flow result processing
1158 vs.DeleteInProgress = true
1159 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301160 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301161
1162 if len(vs.AssociatedFlows) == 0 {
1163 noFlowsPresent = true
1164 }
1165 vpv.VpvLock.Lock()
1166 defer vpv.VpvLock.Unlock()
1167
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301168 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301169
1170 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301171 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301172 }
1173 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 +05301174 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301175 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301176 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301177 }
1178
1179 // Delete the service immediately in case of Force Delete
1180 // This will be enabled when profile reconciliation happens after restore
1181 // of backedup data
1182 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301183 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301184 GetApplication().ServiceByName.Delete(vs.Name)
1185 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1186 }
1187
1188 meterProfiles := make(map[*VoltMeter]bool)
1189
1190 if nil != newSvc {
1191 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1192 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1193 }
1194 skipMeterDeletion := false
1195 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1196 if nil != newSvc && aggMeter.Name == newSvc.AggDsMeterProfile {
1197 skipMeterDeletion = true
1198 }
1199
1200 meterProfiles[aggMeter] = skipMeterDeletion
1201 skipMeterDeletion = false
1202 }
1203 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
1204 if nil != newSvc && dsMeter.Name == newSvc.DsMeterProfile {
1205 skipMeterDeletion = true
1206 }
1207 meterProfiles[dsMeter] = skipMeterDeletion
1208 skipMeterDeletion = false
1209 }
1210 if vs.AggDsMeterID != vs.UsMeterID {
1211 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
1212 if nil != newSvc && usMeter.Name == newSvc.UsMeterProfile {
1213 skipMeterDeletion = true
1214 }
1215 meterProfiles[usMeter] = skipMeterDeletion
1216 }
1217 }
1218
1219 for meter, skipMeterDeletion := range meterProfiles {
1220 if nil == meter {
1221 logger.Debug(ctx, "Null meter found, continuing")
1222 continue
1223 }
1224 if meter.AssociatedServices > 0 {
1225 meter.AssociatedServices--
1226 if meter.AssociatedServices == 0 && !skipMeterDeletion {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301227 logger.Infow(ctx, "Meter should be deleted now\n", log.Fields{"MeterID": meter})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301228 va.UpdateMeterProf(cntx, *meter)
Naveen Sampath04696f72022-06-13 15:19:14 +05301229 }
1230 }
1231 }
1232
1233 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301234 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301235 }
1236
1237 //Delete the per service counter too
1238 va.ServiceCounters.Delete(name)
1239 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301240 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301241 }
1242}
1243
1244//AddFlows - Adds the flow to the service
1245// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301246func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301247
1248 // Using locks instead of concurrent map for PendingFlows to avoid
1249 // race condition during flow response indication processing
1250 vs.ServiceLock.Lock()
1251 defer vs.ServiceLock.Unlock()
1252
1253 for cookie := range flow.SubFlows {
1254 cookie := strconv.FormatUint(cookie, 10)
1255 fe := &FlowEvent{
1256 eType: EventTypeServiceFlowAdded,
1257 device: device.Name,
1258 cookie: cookie,
1259 eventData: vs,
1260 }
1261 device.RegisterFlowAddEvent(cookie, fe)
1262 vs.PendingFlows[cookie] = true
1263 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301264 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301265}
1266
1267//FlowInstallSuccess - Called when corresponding service flow installation is success
1268// If no more pending flows, HSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301269func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301270 if vs.DeleteInProgress {
1271 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1272 return
1273 }
1274 vs.ServiceLock.Lock()
1275
1276 if _, ok := vs.PendingFlows[cookie]; !ok {
1277 logger.Errorw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1278 vs.ServiceLock.Unlock()
1279 return
1280 }
1281
1282 delete(vs.PendingFlows, cookie)
1283 vs.AssociatedFlows[cookie] = true
1284 vs.ServiceLock.Unlock()
1285 var prevBwAvail, presentBwAvail string
1286 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1287 prevBwAvail = bwAvailInfo.PrevBw
1288 presentBwAvail = bwAvailInfo.PresentBw
1289 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301290 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301291 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301292 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301293
1294 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
1295
1296 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1297 if err != nil {
1298 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1299 return
1300 } else if device.State != controller.DeviceStateUP {
1301 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1302 return
1303 }
1304
1305 if vs.Trigger == ServiceVlanUpdate {
1306 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301307 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301308 }
1309 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1310 return
1311 }
1312 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1313}
1314
1315//FlowInstallFailure - Called when corresponding service flow installation is failed
1316// Trigger service failure indication to NB
1317func (vs *VoltService) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
1318 vs.ServiceLock.RLock()
1319
1320 if _, ok := vs.PendingFlows[cookie]; !ok {
1321 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1322 vs.ServiceLock.RUnlock()
1323 return
1324 }
1325 vs.ServiceLock.RUnlock()
1326 logger.Errorw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1327 vs.triggerServiceFailureInd(errorCode, errReason)
1328}
1329
1330//DelFlows - Deletes the flow from the service
1331// Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301332func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301333
1334 if !vs.ForceDelete {
1335 // Using locks instead of concurrent map for AssociatedFlows to avoid
1336 // race condition during flow response indication processing
1337 vs.ServiceLock.Lock()
1338 defer vs.ServiceLock.Unlock()
1339
1340 for cookie := range flow.SubFlows {
1341 cookie := strconv.FormatUint(cookie, 10)
1342 fe := &FlowEvent{
1343 eType: EventTypeServiceFlowRemoved,
1344 cookie: cookie,
1345 eventData: vs,
1346 }
1347 device.RegisterFlowDelEvent(cookie, fe)
1348 }
1349 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301350 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301351}
1352
1353//CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301354func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301355 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301356 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301357 GetApplication().ServiceByName.Delete(vs.Name)
1358 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1359 }
1360}
1361
1362//FlowRemoveSuccess - Called when corresponding service flow removal is success
1363// If no more associated flows, DelHSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301364func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301365
1366 // if vs.DeleteInProgress {
1367 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1368 // return
1369 // }
1370 vs.ServiceLock.Lock()
1371 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1372
1373 if _, ok := vs.AssociatedFlows[cookie]; ok {
1374 delete(vs.AssociatedFlows, cookie)
1375 } else if _, ok := vs.PendingFlows[cookie]; ok {
1376 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})
1377 } else {
1378 logger.Errorw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
1379 }
1380
1381 vs.ServiceLock.Unlock()
1382
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301383 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301384
1385 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
1386
1387 device := GetApplication().GetDevice(vs.Device)
1388 if device == nil {
1389 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1390 return
1391 } else if device.State != controller.DeviceStateUP {
1392 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1393 return
1394 }
1395
1396 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301397 vs.updateVnetProfile(cntx, vs.Device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301398 //Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
1399 return
1400 }
1401 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 +05301402 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301403
1404 return
1405 }
1406 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1407}
1408
1409//FlowRemoveFailure - Called when corresponding service flow installation is failed
1410// Trigger service failure indication to NB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301411func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301412 vs.ServiceLock.RLock()
1413
1414 if _, ok := vs.AssociatedFlows[cookie]; !ok {
1415 logger.Errorw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1416 vs.ServiceLock.RUnlock()
1417 return
1418 }
1419 if vs.DeleteInProgress {
1420 delete(vs.AssociatedFlows, cookie)
1421 }
1422 vs.ServiceLock.RUnlock()
1423 logger.Errorw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1424
1425 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301426 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301427}
1428
1429func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
1430 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1431 if err != nil {
1432 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1433 return
1434 } else if device.State != controller.DeviceStateUP {
1435 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1436 return
1437 }
1438}
1439
1440// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301441func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301442 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301443 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301444 for _, vs := range vss {
1445 b, ok := vs.Value.([]byte)
1446 if !ok {
1447 logger.Warn(ctx, "The value type is not []byte")
1448 continue
1449 }
1450 var vvs VoltService
1451 err := json.Unmarshal(b, &vvs)
1452 if err != nil {
1453 logger.Warn(ctx, "Unmarshal of VNET failed")
1454 continue
1455 }
1456 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301457 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301458 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1459 }
1460
1461 if vvs.VoltServiceOper.DeleteInProgress {
1462 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1463 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1464 }
1465 }
1466}
1467
1468// GetService to get service
1469func (va *VoltApplication) GetService(name string) *VoltService {
1470 if vs, ok := va.ServiceByName.Load(name); ok {
1471 return vs.(*VoltService)
1472 }
1473 return nil
1474}
1475
1476// GetCircuitID to get circuit id
1477func (vs *VoltService) GetCircuitID() []byte {
1478 return []byte(vs.CircuitID)
1479}
1480
1481// GetRemoteID to get remote id
1482func (vs *VoltService) GetRemoteID() []byte {
1483 return []byte(vs.RemoteID)
1484}
1485
1486// IPAssigned to check if ip is assigned
1487func (vs *VoltService) IPAssigned() bool {
1488 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1489 return true
1490 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1491 return true
1492 }
1493 return false
1494}
1495
1496// GetServiceNameFromCookie to get service name from cookie
1497func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
1498
1499 var vlan uint64
1500 vlanControl := (tableMetadata >> 32) & 0xF
1501
1502 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1503 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1504 vlan = (tableMetadata >> 16) & 0xFFFF
1505 } else {
1506 //Fetching CVlan for other vlanControl
1507 vlan = cookie >> 52
1508 }
1509 logger.Infow(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
1510 var vlans []of.VlanType
1511 vlans = append(vlans, of.VlanType(vlan))
1512 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1513 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301514 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301515 } else {
1516 logger.Errorw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
1517 }
1518 return service
1519}
1520
1521//MigrateServicesReqStatus - update vnet request status
1522type MigrateServicesReqStatus string
1523
1524const (
1525 //MigrateSrvsReqInit constant
1526 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
1527 //MigrateSrvsReqDeactTriggered constant
1528 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
1529 //MigrateSrvsReqCompleted constant
1530 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1531)
1532
1533//MigrateServicesRequest - update vnet request params
1534type MigrateServicesRequest struct {
1535 ID string
1536 OldVnetID string
1537 NewVnetID string
1538 ServicesList map[string]bool
1539 DeviceID string
1540 Status MigrateServicesReqStatus
1541 MigrateServicesLock sync.RWMutex
1542}
1543
1544func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
1545
1546 var msr MigrateServicesRequest
1547 msr.OldVnetID = oldVnetID
1548 msr.NewVnetID = newVnetID
1549 msr.ID = id
1550 msr.ServicesList = serviceMap
1551 msr.DeviceID = deviceID
1552 msr.Status = MigrateSrvsReqInit
1553 return &msr
1554}
1555
1556//GetMsrKey - generates migrate service request key
1557func (msr *MigrateServicesRequest) GetMsrKey() string {
1558 return msr.OldVnetID + "-" + msr.ID
1559}
1560
1561// //isRequestComplete - return if all request has been processed and completed
1562// // RequestProcessed indicates that all the profile de-activation has been triggered
1563// // And the associated profiles indicates the profiles awaiting results
1564// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1565// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1566// return (len(edr.AssociatedProfiles) == 0)
1567// }
1568
1569//WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301570func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301571 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)})
1572 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301573 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301574 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301575 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301576 }
1577 }
1578}
1579
1580//MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301581func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301582
1583 logger.Warnw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
1584 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
1585 return errors.New("Old Vnet Id not found")
1586 }
1587 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
1588 return errors.New("New Vnet Id not found")
1589 }
1590
1591 d := va.GetDeviceBySerialNo(serialNum)
1592 if d == nil {
1593 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1594 return errorCodes.ErrDeviceNotFound
1595 }
1596
1597 serviceMap := make(map[string]bool)
1598
1599 for _, service := range serviceList {
1600 serviceMap[service] = false
1601 }
1602 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301603 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301604
1605 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301606 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301607 return nil
1608}
1609
1610//ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301611func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301612 va := GetApplication()
1613 for srv, processed := range msr.ServicesList {
1614
1615 //Indicates new service is already created and only deletion of old one is pending
1616 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301617 va.DelService(cntx, srv, true, nil, true)
1618 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301619 continue
1620 }
1621
1622 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1623 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1624 vs := vsIntf.(*VoltService)
1625 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1626 if vpv == nil {
1627 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
1628 continue
1629 }
1630 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1631 vpv.Blocked = true
1632
1633 // setDeactTrigger := func(key, value interface{}) bool {
1634 // vs := value.(*VoltService)
1635 vs.ServiceLock.Lock()
1636 vs.UpdateInProgress = true
1637 metadata := &MigrateServiceMetadata{
1638 NewVnetID: msr.NewVnetID,
1639 RequestID: msr.ID,
1640 }
1641 vs.Metadata = metadata
1642 vs.ServiceLock.Unlock()
1643
1644 //vpv flows will be removed when last service is removed from it and
1645 // new vpv flows will be installed when new service is added
1646 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301647 vpv.DelTrapFlows(cntx)
1648 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301649 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301650 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301651 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301652 }
1653 } else {
1654 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1655 }
1656 }
1657}
1658
1659//AddMigratingServices - store msr info to device obj
1660func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
1661
1662 var msrMap *util.ConcurrentMap
1663 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1664 msrMap = util.NewConcurrentMap()
1665 } else {
1666 msrMap = msrMapIntf.(*util.ConcurrentMap)
1667 }
1668
1669 msrMap.Set(msr.ID, msr)
1670 logger.Infow(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
1671
1672 d.MigratingServices.Set(msr.OldVnetID, msrMap)
1673 logger.Infow(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
1674
1675}
1676
1677//getMigrateServicesRequest - fetches msr info from device
1678func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
1679 if vd := va.GetDevice(deviceID); vd != nil {
1680 logger.Infow(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
1681 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1682 msrList := msrListIntf.(*util.ConcurrentMap)
1683 logger.Infow(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
1684 if msrObj, ok := msrList.Get(requestID); ok {
1685 return msrObj.(*MigrateServicesRequest)
1686 }
1687
1688 }
1689 }
1690 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
1691 return nil
1692}
1693
1694//updateMigrateServicesRequest - Updates the device with updated msr
1695func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
1696 if vd := va.GetDevice(deviceID); vd != nil {
1697 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1698 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1699 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1700 }
1701 }
1702 }
1703}
1704
1705//updateVnetProfile - Called on flow process completion
1706// Removes old service and creates new VPV & service with udpated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301707func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301708
Tinoj Joseph1d108322022-07-13 10:07:39 +05301709 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 +05301710
1711 nvs := VoltService{}
1712 nvs.VoltServiceCfg = vs.VoltServiceCfg
1713 nvs.Device = vs.Device
1714 nvs.Ipv4Addr = vs.Ipv4Addr
1715 nvs.Ipv6Addr = vs.Ipv6Addr
1716 nvs.UsMeterID = vs.UsMeterID
1717 nvs.DsMeterID = vs.DsMeterID
1718 nvs.AggDsMeterID = vs.AggDsMeterID
1719 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1720 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1721 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1722 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1723 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1724 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1725 nvs.PendingFlows = vs.PendingFlows
1726 nvs.AssociatedFlows = vs.AssociatedFlows
1727 nvs.DeleteInProgress = vs.DeleteInProgress
1728 nvs.ForceDelete = vs.ForceDelete
1729 nvs.BwAvailInfo = vs.BwAvailInfo
1730 nvs.UpdateInProgress = vs.UpdateInProgress
1731
1732 if nvs.DeleteInProgress {
1733 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1734 return
1735 }
1736
1737 metadata := vs.Metadata.(*MigrateServiceMetadata)
1738 oldVnetID := vs.VnetID
1739 nvs.VnetID = metadata.NewVnetID
1740 id := metadata.RequestID
1741 oldSrvName := vs.Name
1742
1743 if metadata == nil || metadata.NewVnetID == "" {
1744 logger.Errorw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
1745 return
1746 }
1747
1748 //First add the new service and then only delete the old service
1749 // Since if post del service in case of pod crash or reboot, the service data will be lost
1750 va := GetApplication()
1751 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1752 vnets := strings.Split(metadata.NewVnetID, "-")
1753 svlan, _ := strconv.Atoi(vnets[0])
1754 nvs.SVlan = of.VlanType(svlan)
1755 nvs.UpdateInProgress = false
1756 nvs.Metadata = nil
1757 nvs.Trigger = ServiceVlanUpdate
1758
1759 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1760 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1761 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1762
1763 //TODO:Nav Pass a copy, not the pointer
1764 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 +05301765 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301766 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1767 }
1768 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1769
1770 msr.ServicesList[oldSrvName] = true
1771 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301772 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301773
1774 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 +05301775 va.DelService(cntx, oldSrvName, true, nil, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301776 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 +05301777 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301778}
1779
1780//serviceMigrated - called on successful service updation
1781// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301782func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301783
1784 msr.MigrateServicesLock.Lock()
1785 defer msr.MigrateServicesLock.Unlock()
1786
1787 delete(msr.ServicesList, serviceName)
1788
1789 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301790 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301791 return
1792 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301793 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301794 //TODO:Nav - Need for any Response to SubMgr?
1795}
1796
1797//TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301798func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1799 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301800}
1801
1802//FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301803func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301804
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301805 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301806 for _, msr := range msrList {
1807 b, ok := msr.Value.([]byte)
1808 if !ok {
1809 logger.Warn(ctx, "The value type is not []byte")
1810 continue
1811 }
1812 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301813 msrAction(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301814 logger.Warnw(ctx, "Triggering Pending Migrate Services Req", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID, "Device": device, "PendingProfiles": len(msr.ServicesList)})
1815
1816 }
1817}
1818
1819// createMigrateServicesFromString to create Service from string
1820func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
1821 var msr MigrateServicesRequest
1822 if err := json.Unmarshal(b, &msr); err == nil {
1823 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
1824
1825 } else {
1826 logger.Warn(ctx, "Unmarshal failed")
1827 }
1828 return &msr
1829}
1830
1831//storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301832func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301833 d := GetApplication().GetDevice(msr.DeviceID)
1834 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301835 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301836}
1837
1838//forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301839func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301840 for srv := range msr.ServicesList {
1841 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301842 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301843 }
1844 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301845 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301846}
1847
1848//DeepEqualServicecfg - checks if the given service cfgs are same
1849func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1850 if nvs.Name != evs.Name {
1851 return false
1852 }
1853 if nvs.UniVlan != evs.UniVlan {
1854 return false
1855 }
1856 if nvs.CVlan != evs.CVlan {
1857 return false
1858 }
1859 if nvs.SVlan != evs.SVlan {
1860 return false
1861 }
1862 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1863 return false
1864 }
1865 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1866 return false
1867 }
1868 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1869 return false
1870 }
1871 if nvs.TechProfileID != evs.TechProfileID {
1872 return false
1873 }
1874 if nvs.CircuitID != evs.CircuitID {
1875 return false
1876 }
1877 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1878 return false
1879 }
1880 if nvs.Port != evs.Port {
1881 return false
1882 }
1883 if nvs.PonPort != evs.PonPort {
1884 return false
1885 }
1886 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1887 return false
1888 }
1889 if nvs.IsOption82Disabled != evs.IsOption82Disabled {
1890 return false
1891 }
1892 if nvs.IgmpEnabled != evs.IgmpEnabled {
1893 return false
1894 }
1895 if nvs.McastService != evs.McastService {
1896 return false
1897 }
1898 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1899 return false
1900 }
1901 if nvs.UsMeterProfile != evs.UsMeterProfile {
1902 return false
1903 }
1904 if nvs.DsMeterProfile != evs.DsMeterProfile {
1905 return false
1906 }
1907 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
1908 return false
1909 }
1910 if nvs.VnetID != evs.VnetID {
1911 return false
1912 }
1913 if nvs.MvlanProfileName != evs.MvlanProfileName {
1914 return false
1915 }
1916 if nvs.RemoteIDType != evs.RemoteIDType {
1917 return false
1918 }
1919 if nvs.SchedID != evs.SchedID {
1920 return false
1921 }
1922 if nvs.AllowTransparent != evs.AllowTransparent {
1923 return false
1924 }
1925 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
1926 return false
1927 }
1928 if nvs.DataRateAttr != evs.DataRateAttr {
1929 return false
1930 }
1931 if nvs.MinDataRateUs != evs.MinDataRateUs {
1932 return false
1933 }
1934 if nvs.MinDataRateDs != evs.MinDataRateDs {
1935 return false
1936 }
1937 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
1938 return false
1939 }
1940 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
1941 return false
1942 }
1943
1944 return true
1945}
1946
1947//TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301948func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301949
1950 //Clear the Flows flag if already set
1951 //This case happens only in case of some race condition
1952 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301953 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301954 logger.Errorw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1955 }
1956 }
1957
1958 if vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301959 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301960 logger.Errorw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1961 }
1962 }
1963
1964 vs.ServiceLock.Lock()
1965 cookieList := []uint64{}
1966 for cookie := range vs.AssociatedFlows {
1967 cookieList = append(cookieList, convertToUInt64(cookie))
1968 }
1969 vs.ServiceLock.Unlock()
1970
1971 if len(cookieList) == 0 {
1972 return false
1973 }
1974
1975 //Trigger Flow Delete
1976 for _, cookie := range cookieList {
1977 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
1978 flow := &of.VoltFlow{}
1979 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1980 subFlow := of.NewVoltSubFlow()
1981 subFlow.Cookie = cookie
1982 flow.SubFlows[cookie] = subFlow
1983 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301984 if err := vs.DelFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301985 logger.Errorw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
1986 }
1987 }
1988 }
1989 return true
1990}
1991
1992//triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
1993func (vs *VoltService) triggerServiceInProgressInd() {
1994}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301995
1996// JsonMarshal wrapper function for json Marshal VoltService
1997func (vs *VoltService) JsonMarshal() ([]byte, error) {
1998 return json.Marshal(VoltService{
1999 VoltServiceCfg: vs.VoltServiceCfg,
2000 VoltServiceOper: VoltServiceOper{
2001 Device: vs.VoltServiceOper.Device,
2002 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
2003 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
2004 UsMeterID: vs.VoltServiceOper.UsMeterID,
2005 DsMeterID: vs.VoltServiceOper.DsMeterID,
2006 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
2007 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
2008 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
2009 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
2010 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
2011 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
2012 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
2013 PendingFlows: vs.VoltServiceOper.PendingFlows,
2014 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
2015 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2016 ForceDelete: vs.VoltServiceOper.ForceDelete,
2017 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2018 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2019 Metadata: vs.VoltServiceOper.Metadata,
2020 },
2021 })
2022}
Tinoj Josephec742f62022-09-29 19:11:10 +05302023
2024// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302025func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302026 var svcList []*VoltService
2027 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2028 va.ServiceByName.Range(func(key, value interface{}) bool {
2029 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302030 if len(deviceID) > 0 {
2031 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302032 if deviceID == vs.Device && portNo == vs.Port {
2033 svcList = append(svcList, vs)
2034 }
2035 } else {
2036 if deviceID == vs.Device {
2037 svcList = append(svcList, vs)
2038 }
2039 }
2040 } else {
2041 svcList = append(svcList, vs)
2042 }
2043 return true
2044 })
2045 return svcList, nil
2046}
2047
2048// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302049func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302050 logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302051 device, err := va.GetDeviceFromPort(portNo)
2052 if err != nil {
2053 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2054 return errorCodes.ErrPortNotFound
2055 }
2056 // If device id is not provided check only port number
2057 if deviceID == DeviceAny {
2058 deviceID = device.Name
2059 } else if deviceID != device.Name {
2060 logger.Errorw(ctx, "Wrong Device ID", log.Fields{"Device": deviceID, "Port": portNo})
2061 return errorCodes.ErrDeviceNotFound
2062 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302063 va.ServiceByName.Range(func(key, value interface{}) bool {
2064 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302065 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302066 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302067 return true
2068 }
2069 if portNo == vs.Port && !vs.IsActivated {
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302070 p := device.GetPort(vs.Port)
Tinoj Josephec742f62022-09-29 19:11:10 +05302071 if p == nil {
2072 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2073 return true
2074 }
2075 logger.Infow(ctx, "Service Activate", log.Fields{"Name": vs.Name})
2076 vs.IsActivated = true
2077 va.ServiceByName.Store(vs.Name, vs)
2078 vs.WriteToDb(cntx)
2079 // If port is already up send indication to vpv
2080 if p.State == PortStateUp {
2081 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2082 // PortUp call initiates flow addition
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302083 vpv.PortUpInd(cntx, device, portNo)
Tinoj Josephec742f62022-09-29 19:11:10 +05302084 } else {
2085 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2086 }
2087 }
2088 }
2089 return true
2090 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302091 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302092}
2093
2094// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302095func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302096 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2097 va.ServiceByName.Range(func(key, value interface{}) bool {
2098 vs := value.(*VoltService)
2099 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302100 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2101 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
2102 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 +05302103 return true
2104 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302105 if portNo == vs.Port && vs.IsActivated {
Tinoj Josephec742f62022-09-29 19:11:10 +05302106 vs.IsActivated = false
2107 va.ServiceByName.Store(vs.Name, vs)
2108 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302109 device, err := va.GetDeviceFromPort(portNo)
2110 if err != nil {
2111 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2112 // So no error is returned
2113 logger.Infow(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2114 return true
2115 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302116 p := device.GetPort(vs.Port)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302117 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable){
Tinoj Josephec742f62022-09-29 19:11:10 +05302118 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2119 // Port down call internally deletes all the flows
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302120 vpv.PortDownInd(cntx, deviceID, portNo, true)
Tinoj Josephec742f62022-09-29 19:11:10 +05302121 if vpv.IgmpEnabled {
2122 va.ReceiverDownInd(cntx, deviceID, portNo)
2123 }
2124 } else {
2125 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2126 }
2127 }
2128 }
2129 return true
2130 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302131 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302132}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302133
Tinoj Josephec742f62022-09-29 19:11:10 +05302134/* GetServicePbit to get first set bit in the pbit map
2135 returns -1 : If configured to match on all pbits
2136 returns 8 : If no pbits are configured
2137 returns first pbit if specific pbit is configured */
2138func (vs *VoltService) GetServicePbit() int {
2139 if vs.IsPbitExist(of.PbitMatchAll) {
2140 return -1
2141 }
2142 for pbit:= 0; pbit < int(of.PbitMatchNone); pbit++ {
2143 if vs.IsPbitExist(of.PbitType(pbit)) {
2144 return pbit
2145 }
2146 }
2147 return int(of.PbitMatchNone)
2148}