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