blob: cf2d1fc00d8c64e58d6ef939291d58a60ba1cff8 [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 "encoding/json"
20 "errors"
21 "net"
22 infraerrorCodes "voltha-go-controller/internal/pkg/errorcodes"
23 "strconv"
24 "sync"
25 "time"
26
27 "github.com/google/gopacket"
28 "github.com/google/gopacket/layers"
29 "go.uber.org/atomic"
30
31 "voltha-go-controller/internal/pkg/controller"
32 cntlr "voltha-go-controller/internal/pkg/controller"
33 "voltha-go-controller/database"
34 "voltha-go-controller/internal/pkg/of"
35 "voltha-go-controller/internal/pkg/util"
36 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
37 "github.com/opencord/voltha-lib-go/v7/pkg/log"
38)
39
40const (
41 // ICMPv6ArpGroupID constant
42 ICMPv6ArpGroupID uint32 = 1
43
44 // Radisys vendor id constant
45 Radisys string = "Radisys"
46)
47
48var (
49 //BroadcastMAC - Broadcast MAC Address
50 BroadcastMAC, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")
51)
52
53// NonZeroMacAddress utility to identify if the MAC address is non-zero.
54// We use zero MAC address as an unset MAC address
55func NonZeroMacAddress(h net.HardwareAddr) bool {
56 for i := 0; i < 6; i++ {
57 if h[i] != 0 {
58 return true
59 }
60 }
61 return false
62}
63
64// VNET package manages the different virtual networks that are part of the
65// the network. In the case of VOLT, the networks can be single tagged or
66// double tagged networks. In addition, the networks may be used for unicast
67// and multicast traffic. The unicast traffic further has two models, the
68// 1:1 and N:1 model. In case of a 1:1 model, the outer tag is same for many
69// subscribers and the inner tag is unique to each subscriber for the same
70// outer tag. The N:1 uses the same inner and outer tags, or for that matter
71// a single tag that can also be shared by subscribers. The VNET implementation
72// manages all these possibilities and the associated configuration.
73
74const (
75 // PbitMatchNone constant
76 PbitMatchNone of.PbitType = 8
77 // PbitMatchAll constant
78 PbitMatchAll of.PbitType = 0xFF
79)
80
81// SVlan - Value of the outer tag if double tagged or the only tag if single
82// tagged
83// SVlanTpid - SVlan Tag Protocol Identifier
84// CVlan - Value of the inner tag. Set to VlanNone if single tagged
85// DhcpRelay - Set to true if the DHCP relay is enabled on the virtual network
86// MacLearning - Set to true if the flows should include MAC address
87// UsDhcpPbit - The pbit used for US DHCP packets
88// DsDhcpPbit - The pbit used for DS DHCP packets
89
90// VnetConfig structure
91type VnetConfig struct {
92 Name string
93 SVlan of.VlanType
94 CVlan of.VlanType
95 UniVlan of.VlanType
96 SVlanTpid layers.EthernetType
97 DhcpRelay bool
98 ArpLearning bool
99 MacLearning MacLearningType
100 PppoeIa bool
101 ONTEtherTypeClassification int
102 VlanControl VlanControl
103 Encapsulation string
104 UsDhcpPbit []of.PbitType
105 DsDhcpPbit []of.PbitType
106 UsIGMPPbit []of.PbitType
107 DsIGMPPbit []of.PbitType
108 DevicesList []string //List of serial number of devices on which this vnet is applied
109 AllowTransparent bool
110 CtrlPktPbitRemark map[of.PbitType]of.PbitType
111}
112
113// VnetOper structure
114type VnetOper struct {
115 PendingDeleteFlow map[string]map[string]bool
116 DeleteInProgress bool
117 PendingDeviceToDelete string
118 VnetLock sync.RWMutex `json:"-"`
119 VnetPortLock sync.RWMutex `json:"-"`
120 AssociatedPorts map[string]bool `json:"-"`
121}
122
123// VoltVnet sructure
124type VoltVnet struct {
125 VnetConfig
126 VnetOper
127 Version string
128}
129
130const (
131 // EncapsulationPPPoEIA constant
132 EncapsulationPPPoEIA string = "PPPoE-IA"
133 // EncapsulationPPPoE constant
134 EncapsulationPPPoE string = "PPPoE"
135 // EncapsulationIPoE constant
136 EncapsulationIPoE string = "IPoE"
137)
138
139// NewVoltVnet is constructor for the VNET structure
140func NewVoltVnet(cfg VnetConfig) *VoltVnet {
141 var vv VoltVnet
142 vv.VnetConfig = cfg
143 if vv.PendingDeleteFlow == nil {
144 vv.PendingDeleteFlow = make(map[string]map[string]bool)
145 }
146 vv.DeleteInProgress = false
147 if cfg.Encapsulation == EncapsulationPPPoEIA {
148 vv.PppoeIa = true
149 }
150 vv.AssociatedPorts = make(map[string]bool)
151 return &vv
152}
153
154//associatePortToVnet - associate a port to Vnet
155func (vv *VoltVnet) associatePortToVnet(port string) {
156 vv.VnetPortLock.Lock()
157 if vv.AssociatedPorts == nil {
158 vv.AssociatedPorts = make(map[string]bool)
159 }
160 vv.AssociatedPorts[port] = true
161 vv.VnetPortLock.Unlock()
162}
163
164//disassociatePortFromVnet - disassociate a port from Vnet and return true if the association map is empty
165func (vv *VoltVnet) disassociatePortFromVnet(device string, port string) {
166 vv.VnetPortLock.Lock()
167 delete(vv.AssociatedPorts, port)
168 logger.Infow(ctx, "Disassociated Port from Vnet", log.Fields{"Device": device, "Port": port, "Vnet": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow, "AssociatedPorts": vv.AssociatedPorts, "DeleteFlag": vv.DeleteInProgress})
169 vv.VnetPortLock.Unlock()
170
171 if vv.DeleteInProgress {
172 if !vv.isAssociatedPortsPresent() {
173 if len(vv.PendingDeleteFlow[device]) == 0 {
174 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vv.Name})
175 GetApplication().deleteVnetConfig(vv)
176 _ = db.DelVnet(vv.Name)
177 } else {
178 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow})
179 }
180 } else {
181 vv.VnetPortLock.RLock()
182 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts})
183 vv.VnetPortLock.RUnlock()
184 }
185 }
186}
187
188func (vv *VoltVnet) isAssociatedPortsPresent() bool {
189 vv.VnetPortLock.RLock()
190 defer vv.VnetPortLock.RUnlock()
191 return len(vv.AssociatedPorts) != 0
192}
193
194// WriteToDb commit the VNET to the database
195func (vv *VoltVnet) WriteToDb() {
196
197 if vv.DeleteInProgress {
198 logger.Warnw(ctx, "Skipping Redis Update for Vnet, Vnet delete in progress", log.Fields{"Vnet": vv.Name})
199 return
200 }
201 vv.ForceWriteToDb()
202}
203
204//ForceWriteToDb force commit a vnet to the DB
205func (vv *VoltVnet) ForceWriteToDb() {
206 vv.VnetPortLock.RLock()
207 defer vv.VnetPortLock.RUnlock()
208 vv.Version = database.PresentVersionMap[database.VnetPath]
209 logger.Debugw(ctx, "Updating VNET....", log.Fields{"vnet": vv})
210 if b, err := json.Marshal(vv); err == nil {
211 if err:= db.PutVnet(vv.Name, string(b)); err != nil {
212 logger.Warnw(ctx, "Add Vnet to DB failed", log.Fields{"vnet name": vv.Name, "Error": err})
213 }
214 }
215}
216
217// VnetKey creates the key using the two VLAN tags
218// We append the two VLAN tags to create a single key
219func VnetKey(otag of.VlanType, itag of.VlanType, utag of.VlanType) string {
220 return strconv.Itoa(int(otag)) + "-" + strconv.Itoa(int(itag)) + "-" + strconv.Itoa(int(utag))
221}
222
223// GetVnet get VNET configuration related functionality associated with VOLT application
224func (va *VoltApplication) GetVnet(otag of.VlanType, itag of.VlanType, utag of.VlanType) *VoltVnet {
225 // When matching VNET, it is expected to match first just the outer
226 // tag, and then the combination to make sure there is no conflict
227 // for the new configuration.
228 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, of.VlanNone, utag)); ok {
229 return vnet.(*VoltVnet)
230 }
231 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, itag, utag)); ok {
232 return vnet.(*VoltVnet)
233 }
234 return nil
235}
236
237// The VNET may also be assigned name for easier references. For now,
238// the VNET is mainly identified by the two VLANs.
239
240// GetVnetByName to get vnet by name
241func (va *VoltApplication) GetVnetByName(name string) *VoltVnet {
242 if vnet, ok := va.VnetsByName.Load(name); ok {
243 return vnet.(*VoltVnet)
244 }
245 return nil
246}
247
248// storeVnetConfig to store vnet config
249func (va *VoltApplication) storeVnetConfig(cfg VnetConfig, vv *VoltVnet) {
250
251 var vnetMap *util.ConcurrentMap
252
253 va.VnetsByTag.Store(VnetKey(cfg.SVlan, cfg.CVlan, cfg.UniVlan), vv)
254 va.VnetsByName.Store(cfg.Name, vv)
255
256 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vv.SVlan); !ok {
257 vnetMap = util.NewConcurrentMap()
258 } else {
259 vnetMap = vnetMapIntf.(*util.ConcurrentMap)
260 }
261 vnetMap.Set(vv, true)
262 va.VnetsBySvlan.Set(vv.SVlan, vnetMap)
263}
264
265// deleteVnetConfig to delete vnet config
266func (va *VoltApplication) deleteVnetConfig(vnet *VoltVnet) {
267 va.VnetsByTag.Delete(VnetKey(vnet.SVlan, vnet.CVlan, vnet.UniVlan))
268 va.VnetsByName.Delete(vnet.Name)
269
270 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vnet.SVlan); ok {
271 vnetMap := vnetMapIntf.(*util.ConcurrentMap)
272 vnetMap.Remove(vnet)
273 va.VnetsBySvlan.Set(vnet.SVlan, vnetMap)
274 }
275}
276
277// AddVnet to add a VNET to the list of VNETs configured.
278func (va *VoltApplication) AddVnet(cfg VnetConfig, oper *VnetOper) error {
279
280 AppMutex.VnetMutex.Lock()
281 var vv *VoltVnet
282 devicesToHandle := []string{}
283 vv = va.GetVnetByName(cfg.Name)
284 if vv != nil {
285 //Could be for another OLT or could be case of backup-restore
286 for _, serialNum := range cfg.DevicesList {
287 if isDeviceInList(serialNum, vv.DevicesList) {
288 //This is backup restore scenario, just update the profile
289 logger.Info(ctx, "Add Vnet : Profile Name already exists with OLT, update-the-profile")
290 continue
291 }
292 devicesToHandle = append(devicesToHandle, serialNum)
293 }
294 if len(devicesToHandle) == 0 {
295 logger.Debug(ctx, "Ignoring Duplicate VNET by name ", log.Fields{"Vnet": cfg.Name})
296 AppMutex.VnetMutex.Unlock()
297 return nil
298 }
299 }
300
301 if vv == nil {
302 vv = NewVoltVnet(cfg)
303 if oper != nil {
304 vv.PendingDeleteFlow = oper.PendingDeleteFlow
305 vv.DeleteInProgress = oper.DeleteInProgress
306 vv.AssociatedPorts = oper.AssociatedPorts
307 vv.PendingDeviceToDelete = oper.PendingDeviceToDelete
308 }
309 devicesToHandle = append(devicesToHandle, cfg.DevicesList...)
310 } else {
311 vv.DevicesList = append(vv.DevicesList, devicesToHandle...)
312 }
313
314 va.storeVnetConfig(cfg, vv)
315 vv.WriteToDb()
316
317 logger.Infow(ctx, "Added VNET TO DB", log.Fields{"cfg": cfg, "devicesToHandle": devicesToHandle})
318
319 //va.PushDevFlowForVlan(vv)
320 AppMutex.VnetMutex.Unlock()
321 return nil
322}
323
324// DelVnet to delete a VNET from the list of VNETs configured
325func (va *VoltApplication) DelVnet(name, deviceSerialNum string) error {
326 logger.Infow(ctx, "Deleting Vnet", log.Fields{"Vnet": name})
327 AppMutex.VnetMutex.Lock()
328 if vnetIntf, ok := va.VnetsByName.Load(name); ok {
329 vnet := vnetIntf.(*VoltVnet)
330 //Delete from mvp list
331 vnet.DevicesList = util.RemoveFromSlice(vnet.DevicesList, deviceSerialNum)
332
333 va.DeleteDevFlowForVlanFromDevice(vnet, deviceSerialNum)
334 if len(vnet.DevicesList) == 0 {
335 vnet.DeleteInProgress = true
336 vnet.PendingDeviceToDelete = deviceSerialNum
337 vnet.ForceWriteToDb()
338 vnet.VnetPortLock.RLock()
339 if len(vnet.PendingDeleteFlow) == 0 && !vnet.isAssociatedPortsPresent() {
340 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
341 va.deleteVnetConfig(vnet)
342 _ = db.DelVnet(vnet.Name)
343 } else {
344 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
345 }
346 vnet.VnetPortLock.RUnlock()
347 } else {
348 //Update the devicelist in db
349 vnet.WriteToDb()
350 }
351 }
352 //TODO: if no vnets are present on device remove icmpv6 group from device
353 AppMutex.VnetMutex.Unlock()
354 return nil
355}
356
357// UpdateVnet to update the VNET with associated service count
358func (va *VoltApplication) UpdateVnet(vv *VoltVnet) error {
359 va.storeVnetConfig(vv.VnetConfig, vv)
360 vv.WriteToDb()
361 logger.Infow(ctx, "Updated VNET TO DB", log.Fields{"vv": vv.VnetConfig})
362 return nil
363}
364
365// ------------------------------------------------------------
366// Manifestation of a VNET on a port is handled below
367// ------------------------------------------------------------
368//
369// The VNET on a port handles everything that is done for a VNET
370// such as DHCP relay state machine, MAC addresses, IP addresses
371// learnt, so on.
372
373// DhcpStatus type
374type DhcpStatus uint8
375
376const (
377 // DhcpStatusNone constant
378 DhcpStatusNone DhcpStatus = 0
379 // DhcpStatusAcked constant
380 DhcpStatusAcked DhcpStatus = 1
381 // DhcpStatusNacked constant
382 DhcpStatusNacked DhcpStatus = 2
383 // EthTypeNone constant
384 EthTypeNone int = 0
385 // EthTypeIPoE constant
386 EthTypeIPoE int = 1
387 // EthTypePPPoE constant
388 EthTypePPPoE int = 2
389)
390
391// VoltPortVnet structure
392type VoltPortVnet struct {
393 Device string
394 Port string
395 PonPort uint32
396 VnetName string
397 SVlan of.VlanType
398 CVlan of.VlanType
399 UniVlan of.VlanType
400 SVlanTpid layers.EthernetType
401 DhcpRelay bool
402 ArpRelay bool
403 PppoeIa bool
404 MacLearning MacLearningType
405 DhcpStatus DhcpStatus
406 DhcpExpiryTime time.Time
407 Dhcp6ExpiryTime time.Time
408 FlowsApplied bool
409 services sync.Map
410 servicesCount *atomic.Uint64
411 Ipv4Addr net.IP
412 Ipv6Addr net.IP
413 MacAddr net.HardwareAddr
414 LearntMacAddr net.HardwareAddr
415 CircuitID []byte //Will not be used
416 RemoteID []byte //Will not be used
417 IsOption82Disabled bool //Will not be used
418 RelayState DhcpRelayState
419 PPPoeState PppoeIaState
420 RelayStatev6 Dhcpv6RelayState
421 IgmpEnabled bool
422 IgmpFlowsApplied bool
423 McastService bool
424 ONTEtherTypeClassification int
425 VlanControl VlanControl
426 MvlanProfileName string
427 Version string
428 McastTechProfileID uint16
429 McastPbit of.PbitType
430 McastUsMeterID uint32
431 AllowTransparent bool
432 VpvLock sync.Mutex `json:"-"`
433 SchedID int
434 DHCPv6DUID [MaxLenDhcpv6DUID]byte
435 PendingFlowLock sync.RWMutex `json:"-"`
436 PendingDeleteFlow map[string]bool
437 DeleteInProgress bool
438 Blocked bool
439 DhcpPbit of.PbitType
440}
441
442//VlanControl vlan control type
443type VlanControl uint8
444
445const (
446 // None constant
447 // ONU and OLT will passthrough UNIVLAN as is to BNG
448 None VlanControl = iota
449
450 // ONUCVlanOLTSVlan constant
451 // Tagged traffic, ONU will replace UNIVLAN with CVLAN and OLT will add SVLAN
452 // Untagged traffic, ONU will add CVLAN and OLT will add SVLAN
453 ONUCVlanOLTSVlan
454
455 // OLTCVlanOLTSVlan constant
456 // Tagged traffic, ONU will passthrough UNIVLAN as is to OLT and
457 // OLT will replace UNIVLAN with CVLAN and add SVLAN
458 OLTCVlanOLTSVlan
459
460 // ONUCVlan constant
461 // Tagged traffic, ONU will replace UNIVLAN with CVLAN
462 // Untagged traffic, ONU will add CVLAN
463 ONUCVlan
464
465 // OLTSVlan constant
466 // UnTagged traffic, OLT will add the SVLAN
467 OLTSVlan
468)
469
470// NewVoltPortVnet is constructor for VoltPortVnet
471func NewVoltPortVnet(vnet *VoltVnet) *VoltPortVnet {
472 var vpv VoltPortVnet
473
474 vpv.VnetName = vnet.Name
475 vpv.SVlan = vnet.SVlan
476 vpv.CVlan = vnet.CVlan
477 vpv.UniVlan = vnet.UniVlan
478 vpv.SVlanTpid = vnet.SVlanTpid
479 vpv.DhcpRelay = vnet.DhcpRelay
480 vpv.DhcpStatus = DhcpStatusNone
481 vpv.PPPoeState = PppoeIaStateNone
482 vpv.ArpRelay = vnet.ArpLearning
483 vpv.PppoeIa = vnet.PppoeIa
484 vpv.VlanControl = vnet.VlanControl
485 vpv.ONTEtherTypeClassification = vnet.ONTEtherTypeClassification
486 vpv.AllowTransparent = vnet.AllowTransparent
487 vpv.FlowsApplied = false
488 vpv.IgmpEnabled = false
489 vpv.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
490 vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
491 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
492 if vpv.VlanControl == ONUCVlan {
493 vpv.CVlan = vpv.SVlan
494 }
495 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
496 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
497 if vpv.VlanControl == OLTSVlan {
498 vpv.CVlan = vpv.UniVlan
499 }
500 vpv.servicesCount = atomic.NewUint64(0)
501 vpv.SchedID = 0
502 vpv.PendingDeleteFlow = make(map[string]bool)
503 vpv.DhcpPbit = vnet.UsDhcpPbit[0]
504 return &vpv
505}
506
507func (vpv *VoltPortVnet) setDevice(device string) {
508
509 if vpv.Device != device && vpv.Device != "" {
510 GetApplication().DisassociateVpvsFromDevice(device, vpv)
511 //TEMP:
512 vpv.printAssociatedVPVs(false)
513 }
514
515 logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": vpv.Device, "Port": vpv.Port, "SVlan": vpv.SVlan})
516
517 vpv.Device = device
518 GetApplication().AssociateVpvsToDevice(device, vpv)
519 //TEMP:
520 vpv.printAssociatedVPVs(true)
521}
522
523//TODO - Nav - Temp
524func (vpv *VoltPortVnet) printAssociatedVPVs(add bool) {
525 logger.Infow(ctx, "Start----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
526 if vMap := GetApplication().GetAssociatedVpvsForDevice(vpv.Device, vpv.SVlan); vMap != nil {
527 vMap.Range(func(key, value interface{}) bool {
528 vpvEntry := key.(*VoltPortVnet)
529 logger.Infow(ctx, "Associated VPVs", log.Fields{"SVlan": vpvEntry.SVlan, "CVlan": vpvEntry.CVlan, "UniVlan": vpvEntry.UniVlan})
530 return true
531 })
532 }
533 logger.Infow(ctx, "End----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
534
535}
536
537// GetCircuitID : The interface to be satisfied by the VoltPortVnet to be a DHCP relay
538// session is implemented below. The main functions still remain in
539// the service.go file.
540func (vpv *VoltPortVnet) GetCircuitID() []byte {
541 return []byte(vpv.CircuitID)
542}
543
544// GetRemoteID to get remote id
545func (vpv *VoltPortVnet) GetRemoteID() []byte {
546 return []byte(vpv.RemoteID)
547}
548
549// GetDhcpState to get dhcp state
550func (vpv *VoltPortVnet) GetDhcpState() DhcpRelayState {
551 return vpv.RelayState
552}
553
554// SetDhcpState to set the dhcp state
555func (vpv *VoltPortVnet) SetDhcpState(state DhcpRelayState) {
556 vpv.RelayState = state
557}
558
559// GetPppoeIaState to get pppoeia state
560func (vpv *VoltPortVnet) GetPppoeIaState() PppoeIaState {
561 return vpv.PPPoeState
562}
563
564// SetPppoeIaState to set pppoeia state
565func (vpv *VoltPortVnet) SetPppoeIaState(state PppoeIaState) {
566 vpv.PPPoeState = state
567}
568
569// GetDhcpv6State to get dhcpv6 state
570func (vpv *VoltPortVnet) GetDhcpv6State() Dhcpv6RelayState {
571 return vpv.RelayStatev6
572}
573
574// SetDhcpv6State to set dhcpv6 state
575func (vpv *VoltPortVnet) SetDhcpv6State(state Dhcpv6RelayState) {
576 vpv.RelayStatev6 = state
577}
578
579// DhcpResultInd for dhcp result indication
580func (vpv *VoltPortVnet) DhcpResultInd(res *layers.DHCPv4) {
581 vpv.ProcessDhcpResult(res)
582}
583
584// Dhcpv6ResultInd for dhcpv6 result indication
585func (vpv *VoltPortVnet) Dhcpv6ResultInd(ipv6Addr net.IP, leaseTime uint32) {
586 vpv.ProcessDhcpv6Result(ipv6Addr, leaseTime)
587}
588
589// GetNniVlans to get nni vlans
590func (vpv *VoltPortVnet) GetNniVlans() (uint16, uint16) {
591 switch vpv.VlanControl {
592 case ONUCVlanOLTSVlan,
593 OLTCVlanOLTSVlan:
594 return uint16(vpv.SVlan), uint16(vpv.CVlan)
595 case ONUCVlan,
596 None:
597 return uint16(vpv.SVlan), uint16(of.VlanNone)
598 case OLTSVlan:
599 return uint16(vpv.SVlan), uint16(of.VlanNone)
600 }
601 return uint16(of.VlanNone), uint16(of.VlanNone)
602}
603
604// GetService to get service
605func (vpv *VoltPortVnet) GetService(name string) (*VoltService, bool) {
606 service, ok := vpv.services.Load(name)
607 if ok {
608 return service.(*VoltService), ok
609 }
610 return nil, ok
611}
612
613// AddService to add service
614func (vpv *VoltPortVnet) AddService(service *VoltService) {
615 vpv.services.Store(service.Name, service)
616 vpv.servicesCount.Inc()
617 logger.Infow(ctx, "Service added/updated to VPV", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "Service": service.Name, "Count": vpv.servicesCount.Load()})
618}
619
620// DelService to delete service
621func (vpv *VoltPortVnet) DelService(service *VoltService) {
622 vpv.services.Delete(service.Name)
623 vpv.servicesCount.Dec()
624
625 // If the only Igmp Enabled service is removed, remove the Igmp trap flow along with it
626 if service.IgmpEnabled {
627 if err := vpv.DelIgmpFlows(); err != nil {
628 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
629 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
630 }
631
632 vpv.IgmpEnabled = false
633 }
634 logger.Infow(ctx, "Service deleted from VPV", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "Service": service.Name, "Count": vpv.servicesCount.Load()})
635}
636
637// ProcessDhcpResult to process dhcp results
638func (vpv *VoltPortVnet) ProcessDhcpResult(res *layers.DHCPv4) {
639 msgType := DhcpMsgType(res)
640 if msgType == layers.DHCPMsgTypeAck {
641 vpv.ProcessDhcpSuccess(res)
642 } else if msgType == layers.DHCPMsgTypeNak {
643 vpv.DhcpStatus = DhcpStatusNacked
644 }
645 vpv.WriteToDb()
646}
647
648// ProcessDhcpSuccess : Learn the IPv4 address allocated to the services and update the
649// the services with the same. This also calls for adding flows
650// for the services as the DHCP procedure is completed
651func (vpv *VoltPortVnet) ProcessDhcpSuccess(res *layers.DHCPv4) {
652 vpv.DhcpStatus = DhcpStatusAcked
653 vpv.Ipv4Addr, _ = GetIpv4Addr(res)
654 logger.Infow(ctx, "Received IPv4 Address", log.Fields{"IP Address": vpv.Ipv4Addr.String()})
655 logger.Infow(ctx, "Services Configured", log.Fields{"Count": vpv.servicesCount.Load()})
656
657 vpv.services.Range(vpv.updateIPv4AndProvisionFlows)
658 vpv.ProcessDhcpv4Options(res)
659}
660
661// ProcessDhcpv4Options : Currently we process lease time and store the validity of the
662// IP address allocated.
663func (vpv *VoltPortVnet) ProcessDhcpv4Options(res *layers.DHCPv4) {
664 for _, o := range res.Options {
665 switch o.Type {
666 case layers.DHCPOptLeaseTime:
667 leasetime := GetIPv4LeaseTime(o)
668 vpv.DhcpExpiryTime = time.Now().Add((time.Duration(leasetime) * time.Second))
669 logger.Infow(ctx, "Lease Expiry Set", log.Fields{"Time": vpv.DhcpExpiryTime})
670 }
671 }
672}
673
674// ProcessDhcpv6Result : Read the IPv6 address allocated to the device and store it on the
675// VNET. The same IPv6 address is also passed to the services. When a
676// service is fetched all the associated information such as MAC address,
677// IPv4 address and IPv6 addresses can be provided.
678func (vpv *VoltPortVnet) ProcessDhcpv6Result(ipv6Addr net.IP, leaseTime uint32) {
679 // TODO: Status based hanlding of flows
680 vpv.Dhcp6ExpiryTime = time.Now().Add((time.Duration(leaseTime) * time.Second))
681 vpv.Ipv6Addr = ipv6Addr
682
683 vpv.services.Range(vpv.updateIPv6AndProvisionFlows)
684 vpv.WriteToDb()
685}
686
687// AddSvcUsMeterToDevice to add service upstream meter info to device
688func AddSvcUsMeterToDevice(key, value interface{}) bool {
689 svc := value.(*VoltService)
690 logger.Info(ctx, "Adding upstream meter profile to device", log.Fields{"ServiceName": svc.Name})
691 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
692 GetApplication().AddMeterToDevice(svc.Port, device.Name, svc.UsMeterID, 0)
693 return true
694 }
695 logger.Errorw(ctx, "Dropping US Meter request: Device not found", log.Fields{"Service": svc})
696 return false
697}
698
699// PushFlowsForPortVnet - triggers flow construction and push for provided VPV
700func (vpv *VoltPortVnet) PushFlowsForPortVnet(d *VoltDevice) {
701
702 vp := d.GetPort(vpv.Port)
703
704 //Ignore if UNI port is not found or not UP
705 if vp == nil || vp.State != PortStateUp {
706 logger.Warnw(ctx, "Ignoring Vlan UP Ind for VPV: Port Not Found/Ready", log.Fields{"Port": vp})
707 return
708 }
709
710 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
711 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Configuration for VPV", log.Fields{"Device": d.Name, "Port": vpv.Port, "DetectedPon": vp.PonPort, "ExpectedPon": vpv.PonPort, "Vnet": vpv.VnetName})
712 return
713 }
714
715 //Disable the flag so that flows can be pushed again
716 // vpv.IgmpFlowsApplied = false
717 // vpv.DsFlowsApplied = false
718 // vpv.UsFlowsApplied = false
719 vpv.VpvLock.Lock()
720 vpv.PortUpInd(d, vpv.Port)
721 vpv.VpvLock.Unlock()
722}
723
724// PortUpInd : When a port transistions to UP state, the indication is passed
725// on to this module via the application. We read the VNET configuration
726// again here to apply the latest configuration if the configuration
727// changed. Thus, a reboot of ONT forces the new configuration to get
728// applied.
729func (vpv *VoltPortVnet) PortUpInd(device *VoltDevice, port string) {
730
731 if vpv.DeleteInProgress {
732 logger.Errorw(ctx, "Ignoring VPV Port UP Ind, VPV deleteion In-Progress", log.Fields{"Device": device, "Port": port, "Vnet": vpv.VnetName})
733 return
734 }
735 vpv.setDevice(device.Name)
736 logger.Infow(ctx, "Port UP Ind, pushing flows for the port", log.Fields{"Device": device, "Port": port, "VnetDhcp": vpv.DhcpRelay, "McastService": vpv.McastService})
737
738 nni, _ := GetApplication().GetNniPort(device.Name)
739 if nni == "" {
740 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name})
741 return
742 }
743
744 if vp := device.GetPort(port); vp != nil {
745
746 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
747 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Config for VPV", log.Fields{"Device": device.Name, "Port": port, "DetectedPon": vp.PonPort, "ExpectedPon": vpv.PonPort, "Vnet": vpv.VnetName})
748 return
749 }
750 }
751
752 if vpv.Blocked {
753 logger.Errorw(ctx, "VPV Bocked for Processing. Ignoring flow push request", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
754 return
755 }
756
757 if vpv.DhcpRelay || vpv.ArpRelay || vpv.PppoeIa {
758 // If MAC Learning is true if no MAC is configured, push DS/US DHCP, US HSIA flows without MAC.
759 // DS HSIA flows are installed after learning the MAC.
760 logger.Infow(ctx, "Port Up - Trap Flows", log.Fields{"Device": device.Name, "Port": port})
761 // no HSIA flows for multicast service
762 if !vpv.McastService {
763 vpv.services.Range(AddUsHsiaFlows)
764 }
765 vpv.AddTrapFlows()
766 if vpv.MacLearning == MacLearningNone || NonZeroMacAddress(vpv.MacAddr) {
767 logger.Infow(ctx, "Port Up - DS Flows", log.Fields{"Device": device.Name, "Port": port})
768 // US & DS DHCP, US HSIA flows are already installed
769 // install only DS HSIA flow here.
770 // no HSIA flows for multicast service
771 if !vpv.McastService {
772 vpv.services.Range(AddDsHsiaFlows)
773 }
774 }
775
776 } else {
777 // DHCP relay is not configured. This implies that the service must use
778 // 1:1 and does not require MAC learning. In a completely uncommon but
779 // plausible case, the MAC address can be learnt from N:1 without DHCP
780 // relay by configuring any unknown MAC address to be reported. This
781 // however is not seen as a real use case.
782 logger.Infow(ctx, "Port Up - Service Flows", log.Fields{"Device": device.Name, "Port": port})
783 if !vpv.McastService {
784 vpv.services.Range(AddUsHsiaFlows)
785 }
786 vpv.AddTrapFlows()
787 if !vpv.McastService {
788 vpv.services.Range(AddDsHsiaFlows)
789 }
790 }
791
792 // Process IGMP proxy - install IGMP trap rules before DHCP trap rules
793 if vpv.IgmpEnabled {
794 logger.Infow(ctx, "Port Up - IGMP Flows", log.Fields{"Device": device.Name, "Port": port})
795 vpv.services.Range(AddSvcUsMeterToDevice)
796 if err := vpv.AddIgmpFlows(); err != nil {
797 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
798 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
799 }
800
801 if vpv.McastService {
802 vpv.services.Range(PostAccessConfigSuccessInd)
803 }
804 }
805
806 vpv.WriteToDb()
807}
808
809// PortDownInd : When the port status changes to down, we delete all configured flows
810// The same indication is also passed to the services enqueued for them
811// to take appropriate actions
812func (vpv *VoltPortVnet) PortDownInd(device string, port string) {
813
814 logger.Infow(ctx, "VPV Port DOWN Ind, deleting all flows for services",
815 log.Fields{"service count": vpv.servicesCount.Load()})
816
817 //vpv.services.Range(DelAllFlows)
818 vpv.DelTrapFlows()
819 vpv.DelHsiaFlows()
820 vpv.WriteToDb()
821 vpv.ClearServiceCounters()
822}
823
824// SetMacAddr : The MAC address is set when a MAC address is learnt through the
825// packets received from the network. Currently, DHCP packets are
826// only packets we learn the MAC address from
827func (vpv *VoltPortVnet) SetMacAddr(addr net.HardwareAddr) {
828
829 //Store Learnt MAC address and return if MACLearning is not enabled
830 vpv.LearntMacAddr = addr
831 if vpv.MacLearning == MacLearningNone || !NonZeroMacAddress(addr) ||
832 (NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn) {
833 return
834 }
835
836 // Compare the two MAC addresses to see if it is same
837 // If they are same, we just return. If not, we perform
838 // actions to address the change in MAC address
839 //if NonZeroMacAddress(vpv.MacAddr) && !util.MacAddrsMatch(vpv.MacAddr, addr) {
840 if !util.MacAddrsMatch(vpv.MacAddr, addr) {
841 expectedPort := GetApplication().GetMacInPortMap(addr)
842 if expectedPort != "" && expectedPort != vpv.Port {
843 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-setmacaddr",
844 log.Fields{"ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": addr.String()})
845 return
846 }
847 if NonZeroMacAddress(vpv.MacAddr) {
848 logger.Warnw(ctx, "MAC Address Changed. Remove old flows (if added) and re-add with updated MAC", log.Fields{"UpdatedMAC": addr})
849
850 // The newly learnt MAC address is different than earlier one.
851 // The existing MAC based HSIA flows need to be undone as the device
852 // may have been changed
853 // Atleast one HSIA flow should be present in adapter to retain the TP and GEM
854 // hence delete one after the other
855 vpv.services.Range(DelUsHsiaFlows)
856 vpv.MacAddr = addr
857 vpv.services.Range(vpv.setLearntMAC)
858 vpv.services.Range(AddUsHsiaFlows)
859 vpv.services.Range(DelDsHsiaFlows)
860 GetApplication().DeleteMacInPortMap(vpv.MacAddr)
861 } else {
862 vpv.MacAddr = addr
863 vpv.services.Range(vpv.setLearntMAC)
864 logger.Infow(ctx, "MAC Address learnt from DHCP or ARP", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
865 }
866 GetApplication().UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
867 } else {
868 logger.Infow(ctx, "Leant MAC Address is same", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
869 }
870
871 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
872 if err != nil {
873 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
874 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
875 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
876 return
877 }
878 // Ds Hsia flows has to be pushed
879 if vpv.FlowsApplied {
880 // no HSIA flows for multicast service
881 if !vpv.McastService {
882 vpv.services.Range(AddDsHsiaFlows)
883 }
884 }
885 vpv.WriteToDb()
886}
887
888// MatchesVlans : If the VNET matches both S and C VLANs, return true. Else, return false
889func (vpv *VoltPortVnet) MatchesVlans(svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) bool {
890 if vpv.SVlan != svlan || vpv.CVlan != cvlan || vpv.UniVlan != univlan {
891 return false
892 }
893 return true
894}
895
896// MatchesCvlan : If the VNET matches CVLAN, return true. Else, return false
897func (vpv *VoltPortVnet) MatchesCvlan(cvlan []of.VlanType) bool {
898 if len(cvlan) != 1 && !vpv.AllowTransparent {
899 return false
900 }
901 if vpv.CVlan != cvlan[0] {
902 return false
903 }
904 return true
905}
906
907// MatchesPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
908func (vpv *VoltPortVnet) MatchesPriority(priority uint8) *VoltService {
909
910 var service *VoltService
911 pbitFound := false
912 matchpbitsFunc := func(key, value interface{}) bool {
913 svc := value.(*VoltService)
914 for _, pbit := range svc.Pbits {
915 if uint8(pbit) == priority {
916 logger.Infow(ctx, "Pbit match found with service",
917 log.Fields{"Pbit": priority, "serviceName": svc.Name})
918 pbitFound = true
919 service = svc
920 return false //Returning false to stop the Range loop
921 }
922 }
923 return true
924 }
925 _ = pbitFound
926 vpv.services.Range(matchpbitsFunc)
927 return service
928}
929
930// GetRemarkedPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
931func (vpv *VoltPortVnet) GetRemarkedPriority(priority uint8) uint8 {
932
933 dsPbit := uint8(0)
934 matchpbitsFunc := func(key, value interface{}) bool {
935 svc := value.(*VoltService)
936 if remarkPbit, ok := svc.DsRemarkPbitsMap[int(priority)]; ok {
937 logger.Infow(ctx, "Pbit match found with service",
938 log.Fields{"Pbit": priority, "serviceName": svc.Name, "remarkPbit": remarkPbit})
939 dsPbit = uint8(remarkPbit)
940 return false //Returning false to stop the Range loop
941 }
942 // When no remarking info is available, remark the incoming pbit
943 // to highest pbit configured for the subscriber (across all subservices associated)
944 svcPbit := uint8(svc.Pbits[0])
945 if svcPbit > dsPbit {
946 dsPbit = svcPbit
947 }
948 return true
949 }
950 vpv.services.Range(matchpbitsFunc)
951 logger.Debugw(ctx, "Remarked Pbit Value", log.Fields{"Incoming": priority, "Remarked": dsPbit})
952 return dsPbit
953}
954
955// AddSvc adds a service on the VNET on a port. The addition is
956// triggered when NB requests for service addition
957func (vpv *VoltPortVnet) AddSvc(svc *VoltService) {
958
959 //vpv.services = append(vpv.services, svc)
960 vpv.AddService(svc)
961 logger.Debugw(ctx, "Added Service to VPV", log.Fields{"Num of SVCs": vpv.servicesCount.Load(), "SVC": svc})
962
963 // Learn the circuit-id and remote-id from the service
964 // TODO: There must be a better way of doing this. This
965 // may be explored
966 if svc.IgmpEnabled {
967 vpv.IgmpEnabled = true
968 }
969 // first time service activation MacLearning will have default value as None.
970 // to handle reciliency if anythng other then None we should retain it .
971 if svc.MacLearning == MacLearningNone {
972 if !vpv.DhcpRelay && !vpv.ArpRelay {
973 svc.MacLearning = MacLearningNone
974 } else if vpv.MacLearning == Learn {
975 svc.MacLearning = Learn
976 } else if vpv.MacLearning == ReLearn {
977 svc.MacLearning = ReLearn
978 }
979 }
980
981 //TODO: Temp Change - Need to address MAC Learning flow issues completely
982 if (svc.MacLearning == Learn || svc.MacLearning == ReLearn) && NonZeroMacAddress(vpv.MacAddr) {
983 svc.MacAddr = vpv.MacAddr
984 } else if vpv.servicesCount.Load() == 1 {
985 vpv.MacAddr = svc.MacAddr
986 }
987
988 vpv.MacLearning = svc.MacLearning
989 vpv.PonPort = svc.PonPort
990 logger.Debugw(ctx, "Added MAC to VPV", log.Fields{"MacLearning": vpv.MacLearning, "VPV": vpv})
991 //Reconfigure Vlans based on Vlan Control type
992 svc.VlanControl = vpv.VlanControl
993 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
994 if vpv.VlanControl == ONUCVlan {
995 svc.CVlan = svc.SVlan
996 }
997 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
998 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
999 if vpv.VlanControl == OLTSVlan {
1000 svc.CVlan = svc.UniVlan
1001 }
1002 if svc.McastService {
1003 vpv.McastService = true
1004 vpv.McastTechProfileID = svc.TechProfileID
1005 //Assumption: Only one Pbit for mcast service
1006 vpv.McastPbit = svc.Pbits[0]
1007 vpv.McastUsMeterID = svc.UsMeterID
1008 vpv.SchedID = svc.SchedID
1009 }
1010 svc.ONTEtherTypeClassification = vpv.ONTEtherTypeClassification
1011 svc.AllowTransparent = vpv.AllowTransparent
1012 svc.SVlanTpid = vpv.SVlanTpid
1013
1014 //Ensure configuring the mvlan profile only once
1015 //One subscriber cannot have multiple mvlan profiles. Only the first configuration is valid
1016 if svc.MvlanProfileName != "" {
1017 if vpv.MvlanProfileName == "" {
1018 vpv.MvlanProfileName = svc.MvlanProfileName
1019 } else {
1020 logger.Warnw(ctx, "Mvlan Profile already configured for subscriber. Ignoring new Mvlan", log.Fields{"Existing Mvlan": vpv.MvlanProfileName, "New Mvlan": svc.MvlanProfileName})
1021 }
1022 }
1023
1024 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
1025 if err != nil {
1026 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
1027 //statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1028 //TODO-COMM: vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1029 return
1030 }
1031
1032 //Push Service Flows if DHCP relay is not configured
1033 //or already DHCP flows are configured for the VPV
1034 //to which the serivce is associated
1035 if vpv.FlowsApplied {
1036 if NonZeroMacAddress(vpv.MacAddr) || svc.MacLearning == MacLearningNone {
1037 svc.AddHsiaFlows()
1038 } else {
1039 if err:= svc.AddUsHsiaFlows(); err != nil {
1040 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1041 }
1042 }
1043 }
1044
1045 //Assumption: Igmp will be enabled only for one service and SubMgr ensure the same
1046 // When already the port is UP and provisioned a service without igmp, then trap flows for subsequent
1047 // service with Igmp Enabled needs to be installed
1048 if svc.IgmpEnabled && vpv.FlowsApplied {
1049 logger.Infow(ctx, "Add Service - IGMP Flows", log.Fields{"Device": vpv.Device, "Port": vpv.Port})
1050 if err := vpv.AddIgmpFlows(); err != nil {
1051 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1052 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1053 }
1054
1055 if vpv.McastService {
1056 //For McastService, send Service Activated indication once IGMP US flow is pushed
1057 vpv.services.Range(PostAccessConfigSuccessInd)
1058 }
1059 }
1060 vpv.WriteToDb()
1061}
1062
1063// setLearntMAC to set learnt mac
1064func (vpv *VoltPortVnet) setLearntMAC(key, value interface{}) bool {
1065 svc := value.(*VoltService)
1066 svc.SetMacAddr(vpv.MacAddr)
1067 svc.WriteToDb()
1068 return true
1069}
1070
1071// PostAccessConfigSuccessInd for posting access config success indication
1072func PostAccessConfigSuccessInd(key, value interface{}) bool {
1073 return true
1074}
1075
1076// updateIPv4AndProvisionFlows to update ipv4 and provisional flows
1077func (vpv *VoltPortVnet) updateIPv4AndProvisionFlows(key, value interface{}) bool {
1078 svc := value.(*VoltService)
1079 logger.Info(ctx, "Updating Ipv4 address for service", log.Fields{"ServiceName": svc.Name})
1080 svc.SetIpv4Addr(vpv.Ipv4Addr)
1081 svc.WriteToDb()
1082
1083 return true
1084}
1085
1086// updateIPv6AndProvisionFlows to update ipv6 and provisional flow
1087func (vpv *VoltPortVnet) updateIPv6AndProvisionFlows(key, value interface{}) bool {
1088 svc := value.(*VoltService)
1089 svc.SetIpv6Addr(vpv.Ipv6Addr)
1090 svc.WriteToDb()
1091
1092 return true
1093}
1094
1095// AddUsHsiaFlows to add upstream hsia flows
1096func AddUsHsiaFlows(key, value interface{}) bool {
1097 svc := value.(*VoltService)
1098 if err:= svc.AddUsHsiaFlows(); err != nil {
1099 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1100 }
1101 return true
1102}
1103
1104// AddDsHsiaFlows to add downstream hsia flows
1105func AddDsHsiaFlows(key, value interface{}) bool {
1106 svc := value.(*VoltService)
1107 if err:= svc.AddDsHsiaFlows(); err != nil {
1108 logger.Warnw(ctx, "Add DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1109 }
1110 return true
1111}
1112
1113// ClearFlagsInService to clear the flags used in service
1114func ClearFlagsInService(key, value interface{}) bool {
1115 svc := value.(*VoltService)
1116 svc.ServiceLock.Lock()
1117 svc.IgmpFlowsApplied = false
1118 svc.DsDhcpFlowsApplied = false
1119 svc.DsHSIAFlowsApplied = false
1120 svc.Icmpv6FlowsApplied = false
1121 svc.UsHSIAFlowsApplied = false
1122 svc.UsDhcpFlowsApplied = false
1123 svc.PendingFlows = make(map[string]bool)
1124 svc.AssociatedFlows = make(map[string]bool)
1125 svc.ServiceLock.Unlock()
1126 svc.WriteToDb()
1127 logger.Debugw(ctx, "Cleared Flow Flags for service", log.Fields{"name": svc.Name})
1128 return true
1129}
1130
1131// DelDsHsiaFlows to delete hsia flows
1132func DelDsHsiaFlows(key, value interface{}) bool {
1133 svc := value.(*VoltService)
1134 if err:= svc.DelDsHsiaFlows(); err != nil {
1135 logger.Warnw(ctx, "Delete DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1136 }
1137 return true
1138}
1139
1140// DelUsHsiaFlows to delete upstream hsia flows
1141func DelUsHsiaFlows(key, value interface{}) bool {
1142 svc := value.(*VoltService)
1143 if err:= svc.DelUsHsiaFlows(); err != nil {
1144 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1145 }
1146 return true
1147}
1148
1149// ClearServiceCounters to clear the service counters
1150func ClearServiceCounters(key, value interface{}) bool {
1151 svc := value.(*VoltService)
1152 //Delete the per service counter too
1153 GetApplication().ServiceCounters.Delete(svc.Name)
1154 if svc.IgmpEnabled && svc.EnableMulticastKPI {
1155 _ = db.DelAllServiceChannelCounter(svc.Name)
1156 }
1157 return true
1158}
1159
1160//AddTrapFlows - Adds US & DS Trap flows
1161func (vpv *VoltPortVnet) AddTrapFlows() {
1162
1163 if !vpv.FlowsApplied || vgcRebooted {
1164 if vpv.DhcpRelay {
1165 if err := vpv.AddUsDhcpFlows(); err != nil {
1166 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1167 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1168 }
1169 if err := vpv.AddDsDhcpFlows(); err != nil {
1170 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1171 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1172 }
1173 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1174 log.Fields{"port": vpv.Port})
1175 //vpv.updateICMPv6McGroup(true)
1176 } else if vpv.ArpRelay {
1177 if err := vpv.AddUsArpFlows(); err != nil {
1178 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1179 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1180 }
1181 logger.Info(ctx, "ARP trap rules not added in downstream direction")
1182
1183 } else if vpv.PppoeIa {
1184 if err := vpv.AddUsPppoeFlows(); err != nil {
1185 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1186 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1187 }
1188 if err := vpv.AddDsPppoeFlows(); err != nil {
1189 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1190 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1191 }
1192 }
1193 vpv.FlowsApplied = true
1194 vpv.WriteToDb()
1195 }
1196}
1197
1198//DelTrapFlows - Removes all US & DS DHCP, IGMP trap flows.
1199func (vpv *VoltPortVnet) DelTrapFlows() {
1200
1201 // Delete HSIA & DHCP flows before deleting IGMP flows
1202 if vpv.FlowsApplied || vgcRebooted {
1203 if vpv.DhcpRelay {
1204 if err:= vpv.DelUsDhcpFlows(); err != nil {
1205 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1206 "UniVlan": vpv.UniVlan, "Error": err})
1207 }
1208 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1209 log.Fields{"port": vpv.Port})
1210 if err := vpv.DelDsDhcpFlows(); err != nil {
1211 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1212 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1213 }
1214 //vpv.updateICMPv6McGroup(false)
1215 } else if vpv.ArpRelay {
1216 if err := vpv.DelUsArpFlows(); err != nil {
1217 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1218 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1219 }
1220 } else if vpv.PppoeIa {
1221 if err := vpv.DelUsPppoeFlows(); err != nil {
1222 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1223 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1224 }
1225 if err := vpv.DelDsPppoeFlows(); err != nil {
1226 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1227 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1228 }
1229 }
1230 vpv.FlowsApplied = false
1231 vpv.WriteToDb()
1232 }
1233 if err:= vpv.DelIgmpFlows(); err != nil {
1234 logger.Warnw(ctx, "Delete igmp flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1235 "UniVlan": vpv.UniVlan, "Error": err})
1236 }
1237}
1238
1239// DelHsiaFlows deletes the service flows
1240func (vpv *VoltPortVnet) DelHsiaFlows() {
1241 // no HSIA flows for multicast service
1242 if !vpv.McastService {
1243 vpv.services.Range(DelUsHsiaFlows)
1244 vpv.services.Range(DelDsHsiaFlows)
1245 }
1246}
1247
1248//ClearServiceCounters - Removes all igmp counters for a service
1249func (vpv *VoltPortVnet) ClearServiceCounters() {
1250 //send flows deleted indication to submgr
1251 vpv.services.Range(ClearServiceCounters)
1252}
1253
1254// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
1255func (vpv *VoltPortVnet) AddUsDhcpFlows() error {
1256 var vd *VoltDevice
1257 device := vpv.Device
1258
1259 if vd = GetApplication().GetDevice(device); vd != nil {
1260 if vd.State != controller.DeviceStateUP {
1261 logger.Errorw(ctx, "Skipping US DHCP Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1262 return nil
1263 }
1264 } else {
1265 logger.Errorw(ctx, "US DHCP Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1266 return errorCodes.ErrDeviceNotFound
1267 }
1268
1269 flows, err := vpv.BuildUsDhcpFlows()
1270 if err == nil {
1271 logger.Debugw(ctx, "Adding US DHCP flows", log.Fields{"Device": device})
1272 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1273 //push ind here ABHI
1274 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1275 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1276 }
1277 } else {
1278 logger.Errorw(ctx, "US DHCP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1279 //push ind here ABHI
1280 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1281 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1282
1283 }
1284 /*
1285 flows, err = vpv.BuildUsDhcp6Flows()
1286 if err == nil {
1287 logger.Debugw(ctx, "Adding US DHCP6 flows", log.Fields{"Device": device})
1288 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1289 //pussh ind here ABHI
1290 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1291 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1292
1293 }
1294 } else {
1295 logger.Errorw(ctx, "US DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1296 //push ind here ABHI
1297 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1298 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1299
1300 }*/
1301 return nil
1302}
1303
1304// AddDsDhcpFlows function pushes the DHCP flows to the VOLTHA via the controller
1305func (vpv *VoltPortVnet) AddDsDhcpFlows() error {
1306
1307 var vd *VoltDevice
1308 device := vpv.Device
1309
1310 if vd = GetApplication().GetDevice(device); vd != nil {
1311 if vd.State != controller.DeviceStateUP {
1312 logger.Errorw(ctx, "Skipping DS DHCP Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1313 return nil
1314 }
1315 } else {
1316 logger.Errorw(ctx, "DS DHCP Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1317 return errorCodes.ErrDeviceNotFound
1318 }
1319 if GetApplication().GetVendorID() != Radisys && vd.GlobalDhcpFlowAdded {
1320 return nil
1321 }
1322
1323 flows, err := vpv.BuildDsDhcpFlows()
1324 if err == nil {
1325 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1326 //push ind here and procced
1327 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1328 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1329
1330 }
1331 } else {
1332 logger.Errorw(ctx, "DS DHCP Flow Add Failed", log.Fields{"Reason": err.Error()})
1333 //send ind here and proceed
1334 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1335 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1336
1337 }
1338 /*
1339 flows, err = vpv.BuildDsDhcp6Flows()
1340 if err == nil {
1341 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1342 //push ind and proceed
1343 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1344 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1345
1346 }
1347 } else {
1348 logger.Errorw(ctx, "DS DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error()})
1349 //Send ind here and proceed
1350 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1351 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1352
1353 }*/
1354 if GetApplication().GetVendorID() != Radisys {
1355 vd.GlobalDhcpFlowAdded = true
1356 }
1357 return nil
1358}
1359
1360// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
1361func (vpv *VoltPortVnet) DelDhcpFlows() {
1362 if err := vpv.DelUsDhcpFlows(); err != nil {
1363 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1364 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1365 }
1366
1367 if err := vpv.DelDsDhcpFlows(); err != nil {
1368 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1369 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1370 }
1371}
1372
1373// DelUsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1374// Write the status of the VPV to the DB once the delete is scheduled
1375// for dispatch
1376func (vpv *VoltPortVnet) DelUsDhcpFlows() error {
1377 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1378 if err != nil {
1379 return err
1380 }
1381
1382 err = vpv.delDhcp4Flows(device)
1383 if err != nil {
1384 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1385 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1386 }
1387 /*
1388 err = vpv.delDhcp6Flows(device)
1389 if err != nil {
1390 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1391 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1392 }*/
1393 return nil
1394}
1395
1396func (vpv *VoltPortVnet) delDhcp4Flows(device *VoltDevice) error {
1397 flows, err := vpv.BuildUsDhcpFlows()
1398 if err == nil {
1399 return vpv.RemoveFlows(device, flows)
1400 }
1401 logger.Errorw(ctx, "US DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1402 return err
1403}
1404/*
1405func (vpv *VoltPortVnet) delDhcp6Flows(device *VoltDevice) error {
1406 flows, err := vpv.BuildUsDhcp6Flows()
1407 if err == nil {
1408 return vpv.RemoveFlows(device, flows)
1409 }
1410 logger.Errorw(ctx, "US DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1411 return err
1412
1413}*/
1414
1415// DelDsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1416// Write the status of the VPV to the DB once the delete is scheduled
1417// for dispatch
1418func (vpv *VoltPortVnet) DelDsDhcpFlows() error {
1419 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1420 if err != nil {
1421 return err
1422 }
1423 err = vpv.delDsDhcp4Flows(device)
1424 if err != nil {
1425 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1426 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1427 }
1428 /*
1429 err = vpv.delDsDhcp6Flows(device)
1430 if err != nil {
1431 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1432 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1433 }*/
1434 return nil
1435}
1436
1437func (vpv *VoltPortVnet) delDsDhcp4Flows(device *VoltDevice) error {
1438 flows, err := vpv.BuildDsDhcpFlows()
1439 if err == nil {
1440 return vpv.RemoveFlows(device, flows)
1441 }
1442 logger.Errorw(ctx, "DS DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1443 return err
1444}
1445
1446/*
1447func (vpv *VoltPortVnet) delDsDhcp6Flows(device *VoltDevice) error {
1448 flows, err := vpv.BuildDsDhcp6Flows()
1449 if err == nil {
1450 return vpv.RemoveFlows(device, flows)
1451 }
1452 logger.Errorw(ctx, "DS DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1453 return err
1454}*/
1455
1456// AddUsArpFlows pushes the ARP flows to the VOLTHA via the controller
1457func (vpv *VoltPortVnet) AddUsArpFlows() error {
1458
1459 var vd *VoltDevice
1460 device := vpv.Device
1461 if vd = GetApplication().GetDevice(device); vd != nil {
1462 if vd.State != controller.DeviceStateUP {
1463 logger.Errorw(ctx, "Skipping US ARP Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1464 return nil
1465 }
1466 } else {
1467 logger.Errorw(ctx, "US ARP Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1468 return errorCodes.ErrDeviceNotFound
1469 }
1470
1471 flows, err := vpv.BuildUsArpFlows()
1472 if err == nil {
1473 logger.Debugw(ctx, "Adding US ARP flows", log.Fields{"Device": device})
1474 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1475 return err1
1476 }
1477 } else {
1478 logger.Errorw(ctx, "US ARP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1479 return err
1480 }
1481 return nil
1482}
1483
1484// DelUsArpFlows delete the ARP flows applied for this Vnet instantiated on the port
1485// Write the status of the VPV to the DB once the delete is scheduled
1486// for dispatch
1487func (vpv *VoltPortVnet) DelUsArpFlows() error {
1488 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1489 if err != nil {
1490 return err
1491 }
1492 flows, err := vpv.BuildUsArpFlows()
1493 if err == nil {
1494 return vpv.RemoveFlows(device, flows)
1495 }
1496 logger.Errorw(ctx, "US ARP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1497 return err
1498}
1499
1500// AddUsPppoeFlows pushes the PPPoE flows to the VOLTHA via the controller
1501func (vpv *VoltPortVnet) AddUsPppoeFlows() error {
1502 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1503
1504 var vd *VoltDevice
1505 device := vpv.Device
1506
1507 if vd = GetApplication().GetDevice(device); vd != nil {
1508 if vd.State != controller.DeviceStateUP {
1509 logger.Errorw(ctx, "Skipping US PPPoE Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1510 return nil
1511 }
1512 } else {
1513 logger.Errorw(ctx, "US PPPoE Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1514 return errorCodes.ErrDeviceNotFound
1515 }
1516
1517 if flows, err := vpv.BuildUsPppoeFlows(); err == nil {
1518 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"Device": device})
1519
1520 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1521 return err1
1522 }
1523 } else {
1524 logger.Errorw(ctx, "US PPPoE Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1525 return err
1526 }
1527 return nil
1528}
1529
1530// AddDsPppoeFlows to add downstream pppoe flows
1531func (vpv *VoltPortVnet) AddDsPppoeFlows() error {
1532 logger.Debugw(ctx, "Adding DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1533 var vd *VoltDevice
1534 device := vpv.Device
1535
1536 if vd = GetApplication().GetDevice(device); vd != nil {
1537 if vd.State != controller.DeviceStateUP {
1538 logger.Errorw(ctx, "Skipping DS PPPoE Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1539 return nil
1540 }
1541 } else {
1542 logger.Errorw(ctx, "DS PPPoE Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1543 return errorCodes.ErrDeviceNotFound
1544 }
1545
1546 flows, err := vpv.BuildDsPppoeFlows()
1547 if err == nil {
1548
1549 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1550 return err1
1551 }
1552 } else {
1553 logger.Errorw(ctx, "DS PPPoE Flow Add Failed", log.Fields{"Reason": err.Error()})
1554 return err
1555 }
1556 return nil
1557}
1558
1559// DelUsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1560// Write the status of the VPV to the DB once the delete is scheduled
1561// for dispatch
1562func (vpv *VoltPortVnet) DelUsPppoeFlows() error {
1563 logger.Debugw(ctx, "Deleting US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1564 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1565 if err != nil {
1566 return err
1567 }
1568 flows, err := vpv.BuildUsPppoeFlows()
1569 if err == nil {
1570 return vpv.RemoveFlows(device, flows)
1571 }
1572 logger.Errorw(ctx, "US PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1573 return err
1574}
1575
1576// DelDsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1577// Write the status of the VPV to the DB once the delete is scheduled
1578// for dispatch
1579func (vpv *VoltPortVnet) DelDsPppoeFlows() error {
1580 logger.Debugw(ctx, "Deleting DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1581 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1582 if err != nil {
1583 return err
1584 }
1585 flows, err := vpv.BuildDsPppoeFlows()
1586 if err == nil {
1587 return vpv.RemoveFlows(device, flows)
1588 }
1589 logger.Errorw(ctx, "DS PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1590 return err
1591}
1592
1593// AddIgmpFlows function pushes the IGMP flows to the VOLTHA via the controller
1594func (vpv *VoltPortVnet) AddIgmpFlows() error {
1595
1596 if !vpv.IgmpFlowsApplied || vgcRebooted {
1597 if vpv.MvlanProfileName == "" {
1598 logger.Info(ctx, "Mvlan Profile not configured. Ignoring Igmp trap flow")
1599 return nil
1600 }
1601 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1602 if err != nil {
1603 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1604 return err
1605 } else if device.State != controller.DeviceStateUP {
1606 logger.Warnw(ctx, "Device state Down. Ignoring US IGMP Flow Push", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan})
1607 return nil
1608 }
1609 flows, err := vpv.BuildIgmpFlows()
1610 if err == nil {
1611 for cookie := range flows.SubFlows {
1612 if vd := GetApplication().GetDevice(device.Name); vd != nil {
1613 cookie := strconv.FormatUint(cookie, 10)
1614 fe := &FlowEvent{
1615 eType: EventTypeUsIgmpFlowAdded,
1616 cookie: cookie,
1617 eventData: vpv,
1618 }
1619 vd.RegisterFlowAddEvent(cookie, fe)
1620 }
1621 }
1622 if err1 := cntlr.GetController().AddFlows(vpv.Port, device.Name, flows); err1 != nil {
1623 return err1
1624 }
1625 } else {
1626 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1627 return err
1628 }
1629 vpv.IgmpFlowsApplied = true
1630 vpv.WriteToDb()
1631 }
1632 return nil
1633}
1634
1635// DelIgmpFlows delete the IGMP flows applied for this Vnet instantiated on the port
1636// Write the status of the VPV to the DB once the delete is scheduled
1637// for dispatch
1638func (vpv *VoltPortVnet) DelIgmpFlows() error {
1639
1640 if vpv.IgmpFlowsApplied || vgcRebooted {
1641 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1642 if err != nil {
1643 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1644 return err
1645 }
1646 flows, err := vpv.BuildIgmpFlows()
1647 if err == nil {
1648 if err1 := vpv.RemoveFlows(device, flows); err1 != nil {
1649 return err1
1650 }
1651 } else {
1652 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1653 return err
1654 }
1655 vpv.IgmpFlowsApplied = false
1656 vpv.WriteToDb()
1657 }
1658 return nil
1659}
1660
1661// BuildUsDhcpFlows builds the US DHCP relay flows for a subscriber
1662// The flows included by this function cover US only as the DS is
1663// created either automatically by the VOLTHA or at the device level
1664// earlier
1665func (vpv *VoltPortVnet) BuildUsDhcpFlows() (*of.VoltFlow, error) {
1666 flow := &of.VoltFlow{}
1667 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1668
1669 logger.Infow(ctx, "Building US DHCP flow", log.Fields{"Port": vpv.Port})
1670 subFlow := of.NewVoltSubFlow()
1671 subFlow.SetTableID(0)
1672
1673 if GetApplication().GetVendorID() == Radisys {
1674 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1675 return nil, err
1676 }
1677 } else {
1678 subFlow.SetMatchVlan(vpv.UniVlan)
1679 subFlow.SetSetVlan(vpv.CVlan)
1680 }
1681 subFlow.SetUdpv4Match()
1682 subFlow.SrcPort = 68
1683 subFlow.DstPort = 67
1684 uniport, err := GetApplication().GetPortID(vpv.Port)
1685 if err != nil {
1686 logger.Errorw(ctx, "Failed to fetch uni port from vpv", log.Fields{"error": err, "port": vpv.Port})
1687 return nil, err
1688 }
1689 subFlow.SetInPort(uniport)
1690 // PortName and PortID to be used for validation of port before flow pushing
1691 flow.PortID = uniport
1692 flow.PortName = vpv.Port
1693 subFlow.SetReportToController()
1694
1695 // Set techprofile, meterid of first service
1696 vpv.services.Range(func(key, value interface{}) bool {
1697 svc := value.(*VoltService)
1698 writemetadata := uint64(svc.TechProfileID) << 32
1699 subFlow.SetWriteMetadata(writemetadata)
1700 subFlow.SetMeterID(svc.UsMeterID)
1701 return false
1702 })
1703
1704 subFlow.SetPcp(vpv.DhcpPbit)
1705 // metadata := uint64(uniport)
1706 // subFlow.SetWriteMetadata(metadata)
1707 allowTransparent := 0
1708 if vpv.AllowTransparent {
1709 allowTransparent = 1
1710 }
1711 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1712 subFlow.SetTableMetadata(metadata)
1713
1714 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1715 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
1716 subFlow.Priority = of.DhcpFlowPriority
1717
1718 flow.SubFlows[subFlow.Cookie] = subFlow
1719 logger.Infow(ctx, "Built US DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1720 return flow, nil
1721}
1722
1723// BuildDsDhcpFlows to build the downstream dhcp flows
1724func (vpv *VoltPortVnet) BuildDsDhcpFlows() (*of.VoltFlow, error) {
1725
1726 logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1727 flow := &of.VoltFlow{}
1728 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1729 subFlow := of.NewVoltSubFlow()
1730 subFlow.SetTableID(0)
1731 // If dhcp trap rule is global rule, No need to match on vlan
1732 if GetApplication().GetVendorID() == Radisys {
1733 vpv.setDsMatchVlan(subFlow)
1734 }
1735 subFlow.SetUdpv4Match()
1736 subFlow.SrcPort = 67
1737 subFlow.DstPort = 68
1738 uniport, _ := GetApplication().GetPortID(vpv.Port)
1739 nni, err := GetApplication().GetNniPort(vpv.Device)
1740 if err != nil {
1741 return nil, err
1742 }
1743 nniport, err := GetApplication().GetPortID(nni)
1744 if err != nil {
1745 return nil, err
1746 }
1747 subFlow.SetInPort(nniport)
1748 // PortName and PortID to be used for validation of port before flow pushing
1749 flow.PortID = uniport
1750 flow.PortName = vpv.Port
1751 // metadata := uint64(uniport)
1752 // subFlow.SetWriteMetadata(metadata)
1753 allowTransparent := 0
1754 if vpv.AllowTransparent {
1755 allowTransparent = 1
1756 }
1757 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1758 subFlow.SetTableMetadata(metadata)
1759 subFlow.SetReportToController()
1760 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1761 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
1762 subFlow.Priority = of.DhcpFlowPriority
1763
1764 flow.SubFlows[subFlow.Cookie] = subFlow
1765 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1766
1767 return flow, nil
1768}
1769
1770// BuildUsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1771// application.
1772func (vpv *VoltPortVnet) BuildUsDhcp6Flows() (*of.VoltFlow, error) {
1773 flow := &of.VoltFlow{}
1774 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1775
1776 logger.Infow(ctx, "Building US DHCPv6 flow", log.Fields{"Port": vpv.Port})
1777 subFlow := of.NewVoltSubFlow()
1778 subFlow.SetTableID(0)
1779
1780 subFlow.SetMatchVlan(vpv.UniVlan)
1781 subFlow.SetSetVlan(vpv.CVlan)
1782 subFlow.SetUdpv6Match()
1783 subFlow.SrcPort = 546
1784 subFlow.DstPort = 547
1785 uniport, err := GetApplication().GetPortID(vpv.Port)
1786 if err != nil {
1787 return nil, err
1788 }
1789 // Set techprofile, meterid of first service
1790 vpv.services.Range(func(key, value interface{}) bool {
1791 svc := value.(*VoltService)
1792 writemetadata := uint64(svc.TechProfileID) << 32
1793 subFlow.SetWriteMetadata(writemetadata)
1794 subFlow.SetMeterID(svc.UsMeterID)
1795 return false
1796 })
1797 subFlow.SetInPort(uniport)
1798 // PortName and PortID to be used for validation of port before flow pushing
1799 flow.PortID = uniport
1800 flow.PortName = vpv.Port
1801 //subFlow.SetMeterId(vpv.UsDhcpMeterId)
1802 // metadata := uint64(uniport)
1803 // subFlow.SetWriteMetadata(metadata)
1804 allowTransparent := 0
1805 if vpv.AllowTransparent {
1806 allowTransparent = 1
1807 }
1808 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1809 subFlow.SetTableMetadata(metadata)
1810 subFlow.SetReportToController()
1811 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1812 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.UsFlowMask
1813 subFlow.Priority = of.DhcpFlowPriority
1814
1815 flow.SubFlows[subFlow.Cookie] = subFlow
1816 logger.Infow(ctx, "Built US DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1817 return flow, nil
1818}
1819
1820// BuildDsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1821// application.
1822func (vpv *VoltPortVnet) BuildDsDhcp6Flows() (*of.VoltFlow, error) {
1823 logger.Infow(ctx, "Building DS DHCPv6 flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1824
1825 flow := &of.VoltFlow{}
1826 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1827 subFlow := of.NewVoltSubFlow()
1828 subFlow.SetTableID(0)
1829
1830 vpv.setDsMatchVlan(subFlow)
1831 subFlow.SetUdpv6Match()
1832 subFlow.SrcPort = 547
1833 subFlow.DstPort = 547
1834 uniport, _ := GetApplication().GetPortID(vpv.Port)
1835 nni, err := GetApplication().GetNniPort(vpv.Device)
1836 if err != nil {
1837 return nil, err
1838 }
1839 nniport, err := GetApplication().GetPortID(nni)
1840 if err != nil {
1841 return nil, err
1842 }
1843 subFlow.SetInPort(nniport)
1844 // PortName and PortID to be used for validation of port before flow pushing
1845 flow.PortID = uniport
1846 flow.PortName = vpv.Port
1847 // metadata := uint64(uniport)
1848 // subFlow.SetWriteMetadata(metadata)
1849 allowTransparent := 0
1850 if vpv.AllowTransparent {
1851 allowTransparent = 1
1852 }
1853 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1854 subFlow.SetTableMetadata(metadata)
1855 subFlow.SetReportToController()
1856 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1857 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.DsFlowMask
1858 subFlow.Priority = of.DhcpFlowPriority
1859
1860 flow.SubFlows[subFlow.Cookie] = subFlow
1861 logger.Infow(ctx, "Built DS DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1862 return flow, nil
1863}
1864
1865// BuildUsArpFlows builds the US ARP relay flows for a subscriber
1866// The flows included by this function cover US only as the DS is
1867// created either automatically by the VOLTHA or at the device level
1868// earlier
1869func (vpv *VoltPortVnet) BuildUsArpFlows() (*of.VoltFlow, error) {
1870 flow := &of.VoltFlow{}
1871 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1872
1873 logger.Infow(ctx, "Building US ARP flow", log.Fields{"Port": vpv.Port})
1874 subFlow := of.NewVoltSubFlow()
1875 subFlow.SetTableID(0)
1876
1877 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1878 subFlow.SetMatchSrcMac(vpv.MacAddr)
1879 }
1880
1881 subFlow.SetMatchDstMac(BroadcastMAC)
1882 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1883 return nil, err
1884 }
1885 subFlow.SetArpMatch()
1886 uniport, err := GetApplication().GetPortID(vpv.Port)
1887 if err != nil {
1888 return nil, err
1889 }
1890 subFlow.SetInPort(uniport)
1891 // PortName and PortID to be used for validation of port before flow pushing
1892 flow.PortID = uniport
1893 flow.PortName = vpv.Port
1894 subFlow.SetReportToController()
1895 allowTransparent := 0
1896 if vpv.AllowTransparent {
1897 allowTransparent = 1
1898 }
1899 metadata := uint64(uniport)
1900 subFlow.SetWriteMetadata(metadata)
1901 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1902 subFlow.SetTableMetadata(metadata)
1903 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<32 | of.DhcpArpFlowMask | of.UsFlowMask
1904 subFlow.Priority = of.ArpFlowPriority
1905
1906 flow.SubFlows[subFlow.Cookie] = subFlow
1907 logger.Infow(ctx, "Built US ARP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1908 return flow, nil
1909}
1910
1911// setUsMatchVlan to set upstream match vlan
1912func (vpv *VoltPortVnet) setUsMatchVlan(flow *of.VoltSubFlow) error {
1913 switch vpv.VlanControl {
1914 case None:
1915 flow.SetMatchVlan(vpv.SVlan)
1916 case ONUCVlanOLTSVlan:
1917 flow.SetMatchVlan(vpv.CVlan)
1918 case OLTCVlanOLTSVlan:
1919 flow.SetMatchVlan(vpv.UniVlan)
1920 //flow.SetSetVlan(vpv.CVlan)
1921 case ONUCVlan:
1922 flow.SetMatchVlan(vpv.SVlan)
1923 case OLTSVlan:
1924 flow.SetMatchVlan(vpv.UniVlan)
1925 //flow.SetSetVlan(vpv.SVlan)
1926 default:
1927 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
1928 return errorCodes.ErrInvalidParamInRequest
1929 }
1930 return nil
1931}
1932
1933// BuildUsPppoeFlows to build upstream pppoe flows
1934func (vpv *VoltPortVnet) BuildUsPppoeFlows() (*of.VoltFlow, error) {
1935
1936 flow := &of.VoltFlow{}
1937 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1938 logger.Infow(ctx, "Building US PPPoE flow", log.Fields{"Port": vpv.Port})
1939 subFlow := of.NewVoltSubFlow()
1940 subFlow.SetTableID(0)
1941
1942 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1943 subFlow.SetMatchSrcMac(vpv.MacAddr)
1944 }
1945
1946 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1947 return nil, err
1948 }
1949 subFlow.SetPppoeDiscoveryMatch()
1950 uniport, err := GetApplication().GetPortID(vpv.Port)
1951 if err != nil {
1952 return nil, err
1953 }
1954 subFlow.SetInPort(uniport)
1955 subFlow.SetReportToController()
1956 // PortName and PortID to be used for validation of port before flow pushing
1957 flow.PortID = uniport
1958 flow.PortName = vpv.Port
1959
1960 allowTransparent := 0
1961 if vpv.AllowTransparent {
1962 allowTransparent = 1
1963 }
1964 metadata := uint64(uniport)
1965 subFlow.SetWriteMetadata(metadata)
1966
1967 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1968 subFlow.SetTableMetadata(metadata)
1969
1970 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits pppoe mask or flow mask |
1971 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.UsFlowMask
1972 subFlow.Priority = of.PppoeFlowPriority
1973
1974 flow.SubFlows[subFlow.Cookie] = subFlow
1975 logger.Infow(ctx, "Built US PPPoE flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1976 return flow, nil
1977}
1978
1979// BuildDsPppoeFlows to build downstream pppoe flows
1980func (vpv *VoltPortVnet) BuildDsPppoeFlows() (*of.VoltFlow, error) {
1981
1982 logger.Infow(ctx, "Building DS PPPoE flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1983 flow := &of.VoltFlow{}
1984 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1985 subFlow := of.NewVoltSubFlow()
1986 subFlow.SetTableID(0)
1987
1988 vpv.setDsMatchVlan(subFlow)
1989 subFlow.SetPppoeDiscoveryMatch()
1990
1991 if NonZeroMacAddress(vpv.MacAddr) {
1992 subFlow.SetMatchDstMac(vpv.MacAddr)
1993 }
1994
1995 uniport, _ := GetApplication().GetPortID(vpv.Port)
1996 nni, err := GetApplication().GetNniPort(vpv.Device)
1997 if err != nil {
1998 return nil, err
1999 }
2000 nniport, err := GetApplication().GetPortID(nni)
2001 if err != nil {
2002 return nil, err
2003 }
2004 subFlow.SetInPort(nniport)
2005 // PortName and PortID to be used for validation of port before flow pushing
2006 flow.PortID = uniport
2007 flow.PortName = vpv.Port
2008 metadata := uint64(uniport)
2009 subFlow.SetWriteMetadata(metadata)
2010 allowTransparent := 0
2011 if vpv.AllowTransparent {
2012 allowTransparent = 1
2013 }
2014 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2015 subFlow.SetTableMetadata(metadata)
2016 subFlow.SetReportToController()
2017 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
2018 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.DsFlowMask
2019 subFlow.Priority = of.PppoeFlowPriority
2020
2021 flow.SubFlows[subFlow.Cookie] = subFlow
2022 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
2023 return flow, nil
2024}
2025
2026// setDsMatchVlan to set downstream match vlan
2027func (vpv *VoltPortVnet) setDsMatchVlan(flow *of.VoltSubFlow) {
2028 switch vpv.VlanControl {
2029 case None:
2030 flow.SetMatchVlan(vpv.SVlan)
2031 case ONUCVlanOLTSVlan,
2032 OLTCVlanOLTSVlan,
2033 ONUCVlan,
2034 OLTSVlan:
2035 flow.SetMatchVlan(vpv.SVlan)
2036 default:
2037 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2038 }
2039}
2040
2041// BuildIgmpFlows builds the US IGMP flows for a subscriber. IGMP requires flows only
2042// in the US direction.
2043func (vpv *VoltPortVnet) BuildIgmpFlows() (*of.VoltFlow, error) {
2044 logger.Infow(ctx, "Building US IGMP Flow", log.Fields{"Port": vpv.Port})
2045 mvp := GetApplication().GetMvlanProfileByName(vpv.MvlanProfileName)
2046 if mvp == nil {
2047 return nil, errors.New("Mvlan Profile configured not found")
2048 }
2049 mvlan := mvp.GetUsMatchVlan()
2050 flow := &of.VoltFlow{}
2051 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2052 subFlow := of.NewVoltSubFlow()
2053 subFlow.SetTableID(0)
2054
2055 if GetApplication().GetVendorID() == Radisys {
2056 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2057 return nil, err
2058 }
2059 } else {
2060 subFlow.SetMatchVlan(vpv.UniVlan)
2061 subFlow.SetSetVlan(vpv.CVlan)
2062 }
2063
2064 uniport, err := GetApplication().GetPortID(vpv.Port)
2065 if err != nil {
2066 return nil, err
2067 }
2068 subFlow.SetInPort(uniport)
2069 // PortName and PortID to be used for validation of port before flow pushing
2070 flow.PortID = uniport
2071 flow.PortName = vpv.Port
2072
2073 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2074 subFlow.SetMatchSrcMac(vpv.MacAddr)
2075 }
2076 logger.Infow(ctx, "Mvlan", log.Fields{"mvlan": mvlan})
2077 //metadata := uint64(mvlan)
2078
2079 if vpv.McastService {
2080 metadata := uint64(vpv.McastUsMeterID)
2081 metadata = metadata | uint64(vpv.McastTechProfileID)<<32
2082 subFlow.SetMatchPbit(vpv.McastPbit)
2083 subFlow.SetMeterID(vpv.McastUsMeterID)
2084 subFlow.SetWriteMetadata(metadata)
2085 } else {
2086 // Set techprofile, meterid of first service
2087 vpv.services.Range(func(key, value interface{}) bool {
2088 svc := value.(*VoltService)
2089 writemetadata := uint64(svc.TechProfileID) << 32
2090 subFlow.SetWriteMetadata(writemetadata)
2091 subFlow.SetMeterID(svc.UsMeterID)
2092 return false
2093 })
2094 }
2095
2096 allowTransparent := 0
2097 if vpv.AllowTransparent {
2098 allowTransparent = 1
2099 }
2100 metadata := uint64(allowTransparent)<<56 | uint64(vpv.SchedID)<<40 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2101 subFlow.SetTableMetadata(metadata)
2102 subFlow.SetIgmpMatch()
2103 subFlow.SetReportToController()
2104 //| 16 bits empty | <32-bits uniport>| 16-bits igmp mask or flow mask |
2105 subFlow.Cookie = uint64(uniport)<<16 | of.IgmpFlowMask | of.UsFlowMask
2106 subFlow.Priority = of.IgmpFlowPriority
2107
2108 flow.SubFlows[subFlow.Cookie] = subFlow
2109 logger.Infow(ctx, "Built US IGMP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2110 return flow, nil
2111}
2112
2113// WriteToDb for writing to database
2114func (vpv *VoltPortVnet) WriteToDb() {
2115 if vpv.DeleteInProgress {
2116 logger.Warnw(ctx, "Skipping Redis Update for VPV, VPV delete in progress", log.Fields{"Vnet": vpv.VnetName, "Port": vpv.Port})
2117 return
2118 }
2119 vpv.ForceWriteToDb()
2120}
2121
2122//ForceWriteToDb force commit a VPV to the DB
2123func (vpv *VoltPortVnet) ForceWriteToDb() {
2124 vpv.PendingFlowLock.RLock()
2125 defer vpv.PendingFlowLock.RUnlock()
2126 vpv.Version = database.PresentVersionMap[database.VpvPath]
2127 if b, err := json.Marshal(vpv); err == nil {
2128 if err := db.PutVpv(vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan), string(b)); err != nil {
2129 logger.Warnw(ctx, "VPV write to DB failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
2130 "UniVlan": vpv.UniVlan, "Error": err})
2131 }
2132 }
2133}
2134
2135// DelFromDb for deleting from database
2136func (vpv *VoltPortVnet) DelFromDb() {
2137 logger.Debugw(ctx, "Deleting VPV from DB", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan})
2138 _ = db.DelVpv(vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan))
2139}
2140
2141// ClearAllServiceFlags to clear all service flags
2142func (vpv *VoltPortVnet) ClearAllServiceFlags() {
2143 vpv.services.Range(ClearFlagsInService)
2144}
2145
2146// ClearAllVpvFlags to clear all vpv flags
2147func (vpv *VoltPortVnet) ClearAllVpvFlags() {
2148 vpv.PendingFlowLock.Lock()
2149 vpv.FlowsApplied = false
2150 vpv.IgmpFlowsApplied = false
2151 vpv.PendingDeleteFlow = make(map[string]bool)
2152 vpv.PendingFlowLock.Unlock()
2153 vpv.WriteToDb()
2154 logger.Debugw(ctx, "Cleared Flow Flags for VPV",
2155 log.Fields{"device": vpv.Device, "port": vpv.Port,
2156 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2157}
2158
2159// CreateVpvFromString to create vpv from string
2160func (va *VoltApplication) CreateVpvFromString(b []byte, hash string) {
2161 var vpv VoltPortVnet
2162 if err := json.Unmarshal(b, &vpv); err == nil {
2163 vnetsByPortsSliceIntf, ok := va.VnetsByPort.Load(vpv.Port)
2164 if !ok {
2165 va.VnetsByPort.Store(vpv.Port, []*VoltPortVnet{})
2166 vnetsByPortsSliceIntf = []*VoltPortVnet{}
2167 }
2168 vpv.servicesCount = atomic.NewUint64(0)
2169 vnetsByPortsSlice := vnetsByPortsSliceIntf.([]*VoltPortVnet)
2170 vnetsByPortsSlice = append(vnetsByPortsSlice, &vpv)
2171 va.VnetsByPort.Store(vpv.Port, vnetsByPortsSlice)
2172 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2173 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2174 vnet.associatePortToVnet(vpv.Port)
2175 }
2176
2177 if vpv.DeleteInProgress {
2178 va.VoltPortVnetsToDelete[&vpv] = true
2179 logger.Warnw(ctx, "VPV (restored) to be deleted", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
2180 }
2181 logger.Debugw(ctx, "Added VPV from string", log.Fields{"port": vpv.Port, "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2182 }
2183}
2184
2185// RestoreVpvsFromDb to restore vpvs from database
2186func (va *VoltApplication) RestoreVpvsFromDb() {
2187 // VNETS must be learnt first
2188 vpvs, _ := db.GetVpvs()
2189 for hash, vpv := range vpvs {
2190 b, ok := vpv.Value.([]byte)
2191 if !ok {
2192 logger.Warn(ctx, "The value type is not []byte")
2193 continue
2194 }
2195 va.CreateVpvFromString(b, hash)
2196 }
2197}
2198
2199// GetVnetByPort : VNET related functionality of VOLT Application here on.
2200// Get the VNET from a port. The port identity is passed as device and port identities in string.
2201// The identity of the VNET is the SVLAN and the CVLAN. Only if the both match the VLAN
2202// is assumed to have matched. TODO: 1:1 should be treated differently and needs to be addressed
2203func (va *VoltApplication) GetVnetByPort(port string, svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) *VoltPortVnet {
2204 if _, ok := va.VnetsByPort.Load(port); !ok {
2205 return nil
2206 }
2207 vpvs, _ := va.VnetsByPort.Load(port)
2208 for _, vpv := range vpvs.([]*VoltPortVnet) {
2209 if vpv.MatchesVlans(svlan, cvlan, univlan) {
2210 return vpv
2211 }
2212 }
2213 return nil
2214}
2215
2216// AddVnetToPort to add vnet to port
2217func (va *VoltApplication) AddVnetToPort(port string, vvnet *VoltVnet, vs *VoltService) *VoltPortVnet {
2218 // The VNET is not on the port and is to be added
2219 logger.Debugw(ctx, "Adding VNET to Port", log.Fields{"Port": port, "VNET": vvnet.Name})
2220 vpv := NewVoltPortVnet(vvnet)
2221 vpv.MacLearning = vvnet.MacLearning
2222 vpv.Port = port
2223 vvnet.associatePortToVnet(port)
2224 if _, ok := va.VnetsByPort.Load(port); !ok {
2225 va.VnetsByPort.Store(port, []*VoltPortVnet{})
2226 }
2227 vpvsIntf, _ := va.VnetsByPort.Load(port)
2228 vpvs := vpvsIntf.([]*VoltPortVnet)
2229 vpvs = append(vpvs, vpv)
2230 va.VnetsByPort.Store(port, vpvs)
2231 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2232
2233 vpv.VpvLock.Lock()
2234 defer vpv.VpvLock.Unlock()
2235
2236 // Add the service that is causing the VNET to be added to the port
2237 vpv.AddSvc(vs)
2238
2239 // Process the PORT UP if the port is already up
2240 d, err := va.GetDeviceFromPort(port)
2241 if err == nil {
2242 vpv.setDevice(d.Name)
2243 p := d.GetPort(port)
2244 if p != nil {
2245
2246 if vs.PonPort != 0xFF && vs.PonPort != p.PonPort {
2247 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Push for VPV", log.Fields{"Device": d.Name, "Port": port, "DetectedPon": p.PonPort, "ExpectedPon": vs.PonPort, "Vnet": vpv.VnetName})
2248 } else {
2249 logger.Infow(ctx, "Checking UNI port state", log.Fields{"State": p.State})
2250 if d.State == controller.DeviceStateUP && p.State == PortStateUp {
2251 vpv.PortUpInd(d, port)
2252 }
2253 }
2254 }
2255 }
2256 vpv.WriteToDb()
2257 return vpv
2258}
2259
2260// DelVnetFromPort for deleting vnet from port
2261func (va *VoltApplication) DelVnetFromPort(port string, vpv *VoltPortVnet) {
2262
2263 //Delete DHCP Session
2264 delDhcpSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan, vpv.DHCPv6DUID)
2265
2266 //Delete PPPoE session
2267 delPppoeIaSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan)
2268
2269 //Delete Mac from MacPortMap
2270 va.DeleteMacInPortMap(vpv.MacAddr)
2271
2272 //Delete VPV
2273 vpvsIntf, ok := va.VnetsByPort.Load(port)
2274 if !ok {
2275 return
2276 }
2277 vpvs := vpvsIntf.([]*VoltPortVnet)
2278 for i, lvpv := range vpvs {
2279 if lvpv == vpv {
2280 logger.Debugw(ctx, "Deleting VPV from port", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan,
2281 "UNIVLAN": vpv.UniVlan})
2282
2283 vpvs = append(vpvs[0:i], vpvs[i+1:]...)
2284
2285 vpv.DeleteInProgress = true
2286 vpv.ForceWriteToDb()
2287
2288 va.VnetsByPort.Store(port, vpvs)
2289 vpv.DelTrapFlows()
2290 vpv.DelHsiaFlows()
2291 va.DisassociateVpvsFromDevice(vpv.Device, vpv)
2292 vpv.PendingFlowLock.RLock()
2293 if len(vpv.PendingDeleteFlow) == 0 {
2294 vpv.DelFromDb()
2295 }
2296 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2297 vnet.disassociatePortFromVnet(vpv.Device, vpv.Port)
2298 }
2299 vpv.PendingFlowLock.RUnlock()
2300 return
2301 }
2302 }
2303}
2304
2305// RestoreVnetsFromDb to restore vnet from port
2306func (va *VoltApplication) RestoreVnetsFromDb() {
2307 // VNETS must be learnt first
2308 vnets, _ := db.GetVnets()
2309 for _, net := range vnets {
2310 b, ok := net.Value.([]byte)
2311 if !ok {
2312 logger.Warn(ctx, "The value type is not []byte")
2313 continue
2314 }
2315 var vnet VoltVnet
2316 err := json.Unmarshal(b, &vnet)
2317 if err != nil {
2318 logger.Warn(ctx, "Unmarshal of VNET failed")
2319 continue
2320 }
2321 logger.Debugw(ctx, "Retrieved VNET", log.Fields{"VNET": vnet.VnetConfig})
2322 if err := va.AddVnet(vnet.VnetConfig, &vnet.VnetOper); err != nil {
2323 logger.Warnw(ctx, "Add Vnet Failed", log.Fields{"Config": vnet.VnetConfig, "Error": err})
2324 }
2325
2326 if vnet.DeleteInProgress {
2327 va.VnetsToDelete[vnet.Name] = true
2328 logger.Warnw(ctx, "Vnet (restored) to be deleted", log.Fields{"Vnet": vnet.Name})
2329 }
2330
2331 }
2332}
2333
2334// GetServiceFromCvlan : Locate a service based on the packet received. The packet contains VLANs that
2335// are used as the key to locate the service. If more than one service is on the
2336// same port (essentially a UNI of ONU), the services must be separated by different
2337// CVLANs
2338func (va *VoltApplication) GetServiceFromCvlan(device, port string, vlans []of.VlanType, priority uint8) *VoltService {
2339 // Fetch the device first to make sure the device exists
2340 dIntf, ok := va.DevicesDisc.Load(device)
2341 if !ok {
2342 return nil
2343 }
2344 d := dIntf.(*VoltDevice)
2345
2346 // If the port is NNI port, the services dont exist on it. The svc then
2347 // must be obtained from a different context and is not included here
2348 if port == d.NniPort {
2349 return nil
2350 }
2351
2352 //To return the matched service
2353 var service *VoltService
2354
2355 // This is an access port and the port should have all the associated
2356 // services which can be uniquely identified by the VLANs in the packet
2357 vnets, ok := va.VnetsByPort.Load(port)
2358
2359 if !ok {
2360 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
2361 return nil
2362 }
2363 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2364 for _, vnet := range vnets.([]*VoltPortVnet) {
2365 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2366 switch vnet.VlanControl {
2367 case ONUCVlanOLTSVlan:
2368 service = vnet.MatchesPriority(priority)
2369 if vnet.MatchesCvlan(vlans) && service != nil {
2370 return service
2371 }
2372 case ONUCVlan,
2373 None:
2374 service = vnet.MatchesPriority(priority)
2375 // In case of DHCP Flow - cvlan == VlanNone
2376 // In case of HSIA Flow - cvlan == Svlan
2377 if len(vlans) == 1 && (vlans[0] == vnet.SVlan || vlans[0] == of.VlanNone) && service != nil {
2378 return service
2379 }
2380 case OLTCVlanOLTSVlan,
2381 OLTSVlan:
2382 service = vnet.MatchesPriority(priority)
2383 if len(vlans) == 1 && vlans[0] == vnet.UniVlan && service != nil {
2384 return service
2385 }
2386 default:
2387 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2388 }
2389 }
2390 return nil
2391}
2392
2393// GetVnetFromFields : Locate a service based on the packet received. The packet contains VLANs that
2394// are used as the key to locate the service. If more than one service is on the
2395// same port (essentially a UNI of ONU), the services must be separated by different
2396// CVLANs
2397func (va *VoltApplication) GetVnetFromFields(device string, port string, vlans []of.VlanType, priority uint8) (*VoltPortVnet, *VoltService) {
2398 // Fetch the device first to make sure the device exists
2399 dIntf, ok := va.DevicesDisc.Load(device)
2400 if !ok {
2401 return nil, nil
2402 }
2403 d := dIntf.(*VoltDevice)
2404
2405 // If the port is NNI port, the services dont exist on it. The svc then
2406 // must be obtained from a different context and is not included here
2407 if port == d.NniPort {
2408 return nil, nil
2409 }
2410
2411 //To return the matched service
2412 var service *VoltService
2413
2414 // This is an access port and the port should have all the associated
2415 // services which can be uniquely identified by the VLANs in the packet
2416 if vnets, ok := va.VnetsByPort.Load(port); ok {
2417 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2418 for _, vnet := range vnets.([]*VoltPortVnet) {
2419 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2420 switch vnet.VlanControl {
2421 case ONUCVlanOLTSVlan:
2422 service = vnet.MatchesPriority(priority)
2423 if vnet.MatchesCvlan(vlans) && service != nil {
2424 return vnet, service
2425 }
2426 case ONUCVlan,
2427 None:
2428 service = vnet.MatchesPriority(priority)
2429 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.SVlan && service != nil {
2430 return vnet, service
2431 }
2432 case OLTCVlanOLTSVlan,
2433 OLTSVlan:
2434 service = vnet.MatchesPriority(priority)
2435 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.UniVlan && service != nil {
2436 return vnet, service
2437 }
2438 default:
2439 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2440 }
2441 }
2442 }
2443 return nil, nil
2444}
2445
2446// GetVnetFromPkt : Locate a service based on the packet received. The packet contains VLANs that
2447// are used as the key to locate the service. If more than one service is on the
2448// same port (essentially a UNI of ONU), the services must be separated by different
2449// CVLANs
2450func (va *VoltApplication) GetVnetFromPkt(device string, port string, pkt gopacket.Packet) (*VoltPortVnet, *VoltService) {
2451 vlans := GetVlans(pkt)
2452 priority := GetPriority(pkt)
2453 return va.GetVnetFromFields(device, port, vlans, priority)
2454}
2455
2456// PushDevFlowForVlan to push icmpv6 flows for vlan
2457func (va *VoltApplication) PushDevFlowForVlan(vnet *VoltVnet) {
2458 logger.Infow(ctx, "PushDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2459 pushflow := func(key interface{}, value interface{}) bool {
2460 device := value.(*VoltDevice)
2461 if !isDeviceInList(device.SerialNum, vnet.DevicesList) {
2462 logger.Info(ctx, "Device not present in vnet device list", log.Fields{"Device": device.SerialNum})
2463 return true
2464 }
2465 if device.State != controller.DeviceStateUP {
2466 logger.Errorw(ctx, "Push Dev Flows Failed - Device state DOWN", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan, "device": device})
2467 return true
2468 }
2469 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2470 logger.Errorw(ctx, "Push Dev Flows Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2471 return true
2472 }
2473
2474 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2475 vnetList := vnetListIntf.(*util.ConcurrentMap)
2476 vnetList.Set(vnet.Name, true)
2477 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2478 logger.Infow(ctx, "Flow already pushed for these Vlans. Adding profile to list", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2479 return true
2480 }
2481 logger.Debugw(ctx, "Configuring Dev Flows Group for device ", log.Fields{"Device": device})
2482 err := ProcessIcmpv6McGroup(device.Name, false)
2483 if err != nil {
2484 logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2485 return true
2486 }
2487 if portID, err := va.GetPortID(device.NniPort); err == nil {
2488 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2489 logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
2490 return true
2491 }
2492
2493 //Pushing ICMPv6 Flow
2494 flow := BuildICMPv6Flow(portID, vnet)
2495 err = cntlr.GetController().AddFlows(device.NniPort, device.Name, flow)
2496 if err != nil {
2497 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2498 return true
2499 }
2500 logger.Infow(ctx, "ICMPv6 Flow Added to Queue", log.Fields{"flow": flow})
2501
2502 // Pushing ARP Flow
2503 flow = BuildDSArpFlow(portID, vnet)
2504 err = cntlr.GetController().AddFlows(device.NniPort, device.Name, flow)
2505 if err != nil {
2506 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2507 return true
2508 }
2509 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2510
2511 vnetList := util.NewConcurrentMap()
2512 vnetList.Set(vnet.Name, true)
2513 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2514 }
2515 return true
2516 }
2517 va.DevicesDisc.Range(pushflow)
2518}
2519
2520// PushDevFlowForDevice to push icmpv6 flows for device
2521func (va *VoltApplication) PushDevFlowForDevice(device *VoltDevice) {
2522 logger.Infow(ctx, "PushDevFlowForDevice", log.Fields{"device": device})
2523
2524 logger.Debugw(ctx, "Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2525 err := ProcessIcmpv6McGroup(device.Name, false)
2526 if err != nil {
2527 logger.Warnw(ctx, "Configuring ICMPv6 Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2528 return
2529 }
2530 pushicmpv6 := func(key, value interface{}) bool {
2531 vnet := value.(*VoltVnet)
2532 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2533 vnetList := vnetListIntf.(*util.ConcurrentMap)
2534 vnetList.Set(vnet.Name, true)
2535 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2536 logger.Infow(ctx, "Flow already pushed for these Vlans. Adding profile to list", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2537 return true
2538 }
2539 nniPortID, err := va.GetPortID(device.NniPort)
2540 if err != nil {
2541 logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2542 }
2543 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2544 logger.Warnw(ctx, "Push ICMPv6 Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2545 return true
2546 }
2547 flow := BuildICMPv6Flow(nniPortID, vnet)
2548 err = cntlr.GetController().AddFlows(device.NniPort, device.Name, flow)
2549 if err != nil {
2550 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2551 return true
2552 }
2553 logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
2554
2555 flow = BuildDSArpFlow(nniPortID, vnet)
2556 err = cntlr.GetController().AddFlows(device.NniPort, device.Name, flow)
2557 if err != nil {
2558 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2559 return true
2560 }
2561 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2562
2563 vnetList := util.NewConcurrentMap()
2564 vnetList.Set(vnet.Name, true)
2565 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2566 return true
2567 }
2568 va.VnetsByName.Range(pushicmpv6)
2569}
2570
2571// DeleteDevFlowForVlan to delete icmpv6 flow for vlan
2572func (va *VoltApplication) DeleteDevFlowForVlan(vnet *VoltVnet) {
2573 logger.Infow(ctx, "DeleteDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2574 delflows := func(key interface{}, value interface{}) bool {
2575 device := value.(*VoltDevice)
2576
2577 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2578 vnetList := vnetListIntf.(*util.ConcurrentMap)
2579 vnetList.Remove(vnet.Name)
2580 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2581 if vnetList.Length() != 0 {
2582 logger.Warnw(ctx, "Similar VNet associated to diff service. Not removing ICMPv6 flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2583 return true
2584 }
2585 }
2586 if portID, err := va.GetPortID(device.NniPort); err == nil {
2587 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2588 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2589 return true
2590 }
2591 //Pushing ICMPv6 Flow
2592 flow := BuildICMPv6Flow(portID, vnet)
2593 flow.ForceAction = true
2594 err := vnet.RemoveFlows(device, flow)
2595 if err != nil {
2596 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2597 return true
2598 }
2599 logger.Infow(ctx, "ICMPv6 Flow Delete Added to Queue", log.Fields{"flow": flow})
2600
2601 //Pushing ARP Flow
2602 flow = BuildDSArpFlow(portID, vnet)
2603 flow.ForceAction = true
2604 err = vnet.RemoveFlows(device, flow)
2605 if err != nil {
2606 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2607 return true
2608 }
2609 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2610
2611 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2612 }
2613 return true
2614 }
2615 va.DevicesDisc.Range(delflows)
2616}
2617
2618// DeleteDevFlowForDevice to delete icmpv6 flow for device
2619func (va *VoltApplication) DeleteDevFlowForDevice(device *VoltDevice) {
2620 logger.Infow(ctx, "DeleteDevFlowForDevice", log.Fields{"Device": device})
2621 delicmpv6 := func(key, value interface{}) bool {
2622 vnet := value.(*VoltVnet)
2623 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2624 vnetList := vnetListIntf.(*util.ConcurrentMap)
2625 vnetList.Remove(vnet.Name)
2626 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2627 if vnetList.Length() != 0 {
2628 logger.Warnw(ctx, "Similar VNet associated to diff service. Not removing ICMPv6 flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2629 return true
2630 }
2631 } else {
2632 logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
2633 return true
2634 }
2635 nniPortID, err := va.GetPortID(device.NniPort)
2636 if err != nil {
2637 logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2638 }
2639 flow := BuildICMPv6Flow(nniPortID, vnet)
2640 flow.ForceAction = true
2641 err = vnet.RemoveFlows(device, flow)
2642 if err != nil {
2643 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2644 return true
2645 }
2646
2647 flow = BuildDSArpFlow(nniPortID, vnet)
2648 flow.ForceAction = true
2649 err = vnet.RemoveFlows(device, flow)
2650 if err != nil {
2651 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2652 return true
2653 }
2654
2655 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2656 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2657 return true
2658 }
2659 va.VnetsByName.Range(delicmpv6)
2660 logger.Debugw(ctx, "De-Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2661 err := ProcessIcmpv6McGroup(device.Name, true)
2662 if err != nil {
2663 logger.Warnw(ctx, "De-Configuring ICMPv6 Group on device failed ", log.Fields{"Device": device.Name, "err": err})
2664 return
2665 }
2666}
2667
2668// DeleteDevFlowForVlanFromDevice to delete icmpv6 flow for vlan from device
2669func (va *VoltApplication) DeleteDevFlowForVlanFromDevice(vnet *VoltVnet, deviceSerialNum string) {
2670 logger.Infow(ctx, "DeleteDevFlowForVlanFromDevice", log.Fields{"Device-serialNum": deviceSerialNum, "SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2671 delflows := func(key interface{}, value interface{}) bool {
2672 device := value.(*VoltDevice)
2673 if device.SerialNum != deviceSerialNum {
2674 return true
2675 }
2676 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2677 vnetList := vnetListIntf.(*util.ConcurrentMap)
2678 vnetList.Remove(vnet.Name)
2679 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2680 if vnetList.Length() != 0 {
2681 logger.Warnw(ctx, "Similar VNet associated to diff service. Not removing ICMPv6 flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2682 return true
2683 }
2684 } else if !vgcRebooted && len(vnet.DevicesList) != 0 {
2685 // Return only in-case of non-reboot/delete scenario. Else, the flows need to be force removed
2686 // DeviceList check is there to avoid dangling flow in-case of pod restart during service de-activation.
2687 // The step will be as follow:
2688 // 1. Deact Service
2689 // 2. Pod Reboot
2690 // 3. Pending Delete Service triggered
2691 // 4. Del Service Ind followed by DelVnet req from NB
2692 // 5. If Vlan status response is awaited, the ConfiguredVlanForDeviceFlows cache will not have flow info
2693 // hence the flow will not be cleared
2694 logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
2695 return true
2696 }
2697 if portID, err := va.GetPortID(device.NniPort); err == nil {
2698 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2699 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2700 return false
2701 }
2702 flow := BuildICMPv6Flow(portID, vnet)
2703 flow.ForceAction = true
2704 if err := vnet.RemoveFlows(device, flow); err != nil {
2705 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2706 }
2707 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2708
2709 flow = BuildDSArpFlow(portID, vnet)
2710 flow.ForceAction = true
2711 if err := vnet.RemoveFlows(device, flow); err != nil {
2712 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2713 }
2714 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2715 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2716 }
2717 return false
2718 }
2719 va.DevicesDisc.Range(delflows)
2720}
2721
2722// BuildICMPv6Flow to Build DS flow for ICMPv6
2723func BuildICMPv6Flow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
2724 logger.Info(ctx, "Building ICMPv6 MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2725 flow := &of.VoltFlow{}
2726 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2727 subFlow := of.NewVoltSubFlow()
2728
2729 subFlow.SetICMPv6Match()
2730 subFlow.SetMatchVlan(vnet.SVlan)
2731 subFlow.SetInPort(inport)
2732 subFlow.SetPopVlan()
2733 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2734 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.IgmpFlowMask | of.DsFlowMask
2735 subFlow.Priority = of.McFlowPriority
2736 var metadata uint64
2737 if vnet.VlanControl == None {
2738 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2739 } else {
2740 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2741 }
2742 subFlow.SetTableMetadata(metadata)
2743 metadata = uint64(vnet.setPbitRemarking())
2744
2745 logger.Infow(ctx, "ICMPv6 Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2746 subFlow.SetWriteMetadata(metadata)
2747 flow.SubFlows[subFlow.Cookie] = subFlow
2748 return flow
2749}
2750
2751//BuildDSArpFlow Builds DS flow for ARP
2752func BuildDSArpFlow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
2753 logger.Info(ctx, "Building ARP MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2754
2755 flow := &of.VoltFlow{}
2756 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2757 subFlow := of.NewVoltSubFlow()
2758
2759 BcastMAC, _ := net.ParseMAC("FF:FF:FF:FF:FF:FF")
2760 subFlow.SetArpMatch()
2761 subFlow.SetMatchDstMac(BcastMAC)
2762 subFlow.SetMatchVlan(vnet.SVlan)
2763 subFlow.SetInPort(inport)
2764 subFlow.SetPopVlan()
2765 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2766
2767 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.DsArpFlowMask | of.DsFlowMask
2768 subFlow.Priority = of.McFlowPriority
2769
2770 var metadata uint64
2771 if vnet.VlanControl == None {
2772 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2773 } else {
2774 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2775 }
2776 subFlow.SetTableMetadata(metadata)
2777 metadata = uint64(vnet.setPbitRemarking())
2778 subFlow.SetWriteMetadata(metadata)
2779
2780 flow.SubFlows[subFlow.Cookie] = subFlow
2781 logger.Infow(ctx, "ARP Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2782 return flow
2783}
2784
2785// setPbitRemarking to set Pbit remarking
2786func (vv *VoltVnet) setPbitRemarking() uint32 {
2787
2788 // Remarkable
2789 // Remarked Pbit Pbit
2790 // |-----------------------------| |------|
2791 // |7| |6| |5| |4| |3| |2| |1| |0| 76543210
2792 // 000 000 000 000 000 000 000 000 00000000
2793
2794 // Eg:
2795 // For 6:3 & 7:1
2796 // 001 011 000 000 000 000 000 000 11000000
2797
2798 var remarkable uint8
2799 var remarked uint32
2800 for refPbit, remarkPbit := range vv.CtrlPktPbitRemark {
2801 remarkable = remarkable | 1<<refPbit
2802 remarked = remarked | uint32(remarkPbit)<<(refPbit*3)
2803 }
2804 return remarked<<8 | uint32(remarkable)
2805}
2806
2807// ProcessIcmpv6McGroup to add icmpv6 multicast group
2808func ProcessIcmpv6McGroup(device string, delete bool) error {
2809
2810 logger.Info(ctx, "Creating ICMPv6 MC Group")
2811 va := GetApplication()
2812 vd := va.GetDevice(device)
2813 group := &of.Group{}
2814 group.GroupID = ICMPv6ArpGroupID
2815 group.Device = device
2816 if delete {
2817 if !vd.icmpv6GroupAdded {
2818 logger.Info(ctx, "ICMPv6 MC Group is already deleted. Ignoring icmpv6 group Delete")
2819 return nil //TODO
2820 }
2821 vd.icmpv6GroupAdded = false
2822 group.Command = of.GroupCommandDel
2823 group.ForceAction = true
2824 } else {
2825 if vd.icmpv6GroupAdded {
2826 logger.Info(ctx, "ICMPv6 MC Group is already added. Ignoring icmpv6 group Add")
2827 return nil //TODO
2828 }
2829 vd.icmpv6GroupAdded = true
2830 group.Command = of.GroupCommandAdd
2831 receivers := GetApplication().GetIcmpv6Receivers(device)
2832 group.Buckets = append(group.Buckets, receivers...)
2833 }
2834 logger.Infow(ctx, "ICMPv6 MC Group Action", log.Fields{"Device": device, "Delete": delete})
2835 port, _ := GetApplication().GetNniPort(device)
2836 err := cntlr.GetController().GroupUpdate(port, device, group)
2837 return err
2838}
2839
2840//isVlanMatching - checks is vlans matches with vpv based on vlan control
2841func (vpv *VoltPortVnet) isVlanMatching(cvlan of.VlanType, svlan of.VlanType) bool {
2842
2843 switch vpv.VlanControl {
2844 case ONUCVlanOLTSVlan,
2845 OLTCVlanOLTSVlan:
2846 if vpv.SVlan == svlan && vpv.CVlan == cvlan {
2847 return true
2848 }
2849 case ONUCVlan,
2850 OLTSVlan,
2851 None:
2852 if vpv.SVlan == svlan {
2853 return true
2854 }
2855 default:
2856 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2857 }
2858 return false
2859}
2860
2861//PushFlows - Triggers flow addition after registering for flow indication event
2862func (vpv *VoltPortVnet) PushFlows(device *VoltDevice, flow *of.VoltFlow) error {
2863
2864 for cookie := range flow.SubFlows {
2865 cookie := strconv.FormatUint(cookie, 10)
2866 fe := &FlowEvent{
2867 eType: EventTypeControlFlowAdded,
2868 cookie: cookie,
2869 eventData: vpv,
2870 }
2871 device.RegisterFlowAddEvent(cookie, fe)
2872 }
2873 return cntlr.GetController().AddFlows(vpv.Port, device.Name, flow)
2874}
2875
2876//FlowInstallFailure - Process flow failure indication and triggers HSIA failure for all associated services
2877func (vpv *VoltPortVnet) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
2878
2879 sendFlowFailureInd := func(key, value interface{}) bool {
2880 //svc := value.(*VoltService)
2881 //TODO-COMM: svc.triggerServiceFailureInd(errorCode, errReason)
2882 return true
2883 }
2884 logger.Errorw(ctx, "Control Flow Add Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2885 vpv.services.Range(sendFlowFailureInd)
2886}
2887
2888//RemoveFlows - Triggers flow deletion after registering for flow indication event
2889func (vpv *VoltPortVnet) RemoveFlows(device *VoltDevice, flow *of.VoltFlow) error {
2890
2891 vpv.PendingFlowLock.Lock()
2892 defer vpv.PendingFlowLock.Unlock()
2893
2894 for cookie := range flow.SubFlows {
2895 cookie := strconv.FormatUint(cookie, 10)
2896 fe := &FlowEvent{
2897 eType: EventTypeControlFlowRemoved,
2898 device: device.Name,
2899 cookie: cookie,
2900 eventData: vpv,
2901 }
2902 device.RegisterFlowDelEvent(cookie, fe)
2903 vpv.PendingDeleteFlow[cookie] = true
2904 }
2905 return cntlr.GetController().DelFlows(vpv.Port, device.Name, flow)
2906}
2907
2908//CheckAndDeleteVpv - remove VPV from DB is there are no pending flows to be removed
2909func (vpv *VoltPortVnet) CheckAndDeleteVpv() {
2910 vpv.PendingFlowLock.RLock()
2911 defer vpv.PendingFlowLock.RUnlock()
2912 if !vpv.DeleteInProgress {
2913 return
2914 }
2915 if len(vpv.PendingDeleteFlow) == 0 && !vpv.FlowsApplied {
2916 logger.Infow(ctx, "All Flows removed for VPV. Triggering VPV Deletion from DB", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
2917 vpv.DelFromDb()
2918 logger.Infow(ctx, "Deleted VPV from DB/Cache successfully", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
2919 }
2920}
2921
2922//FlowRemoveSuccess - Process flow success indication
2923func (vpv *VoltPortVnet) FlowRemoveSuccess(cookie string, device string) {
2924 vpv.PendingFlowLock.Lock()
2925 logger.Infow(ctx, "VPV Flow Remove Success Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "Device": device})
2926
2927 delete(vpv.PendingDeleteFlow, cookie)
2928 vpv.PendingFlowLock.Unlock()
2929 vpv.CheckAndDeleteVpv()
2930 vpv.WriteToDb()
2931}
2932
2933//FlowRemoveFailure - Process flow failure indication and triggers Del HSIA failure for all associated services
2934func (vpv *VoltPortVnet) FlowRemoveFailure(cookie string, device string, errorCode uint32, errReason string) {
2935 vpv.PendingFlowLock.Lock()
2936
2937 logger.Errorw(ctx, "VPV Flow Remove Failure Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
2938
2939 sendFlowFailureInd := func(key, value interface{}) bool {
2940 svc := value.(*VoltService)
2941 svc.triggerServiceFailureInd(errorCode, errReason)
2942 return true
2943 }
2944 logger.Errorw(ctx, "Control Flow Del Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2945 vpv.services.Range(sendFlowFailureInd)
2946
2947 if vpv.DeleteInProgress {
2948 delete(vpv.PendingDeleteFlow, cookie)
2949 vpv.PendingFlowLock.Unlock()
2950 vpv.CheckAndDeleteVpv()
2951 } else {
2952 vpv.PendingFlowLock.Unlock()
2953 vpv.WriteToDb()
2954 }
2955}
2956
2957//RemoveFlows - Triggers flow deletion after registering for flow indication event
2958func (vv *VoltVnet) RemoveFlows(device *VoltDevice, flow *of.VoltFlow) error {
2959
2960 vv.VnetLock.Lock()
2961 defer vv.VnetLock.Unlock()
2962
2963 var flowMap map[string]bool
2964 var ok bool
2965
2966 for cookie := range flow.SubFlows {
2967 cookie := strconv.FormatUint(cookie, 10)
2968 fe := &FlowEvent{
2969 eType: EventTypeDeviceFlowRemoved,
2970 device: device.Name,
2971 cookie: cookie,
2972 eventData: vv,
2973 }
2974 device.RegisterFlowDelEvent(cookie, fe)
2975 if flowMap, ok = vv.PendingDeleteFlow[device.Name]; !ok {
2976 flowMap = make(map[string]bool)
2977 }
2978 flowMap[cookie] = true
2979 vv.PendingDeleteFlow[device.Name] = flowMap
2980 }
2981 vv.WriteToDb()
2982 return cntlr.GetController().DelFlows(device.NniPort, device.Name, flow)
2983}
2984
2985//CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
2986func (vv *VoltVnet) CheckAndDeleteVnet(device string) {
2987 if !vv.DeleteInProgress {
2988 return
2989 }
2990 vv.VnetPortLock.RLock()
2991 if len(vv.PendingDeleteFlow[device]) == 0 && !vv.isAssociatedPortsPresent() {
2992 logger.Warnw(ctx, "Deleting Vnet : All flows removed", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
2993 GetApplication().deleteVnetConfig(vv)
2994 _ = db.DelVnet(vv.Name)
2995 logger.Infow(ctx, "Deleted Vnet from DB/Cache successfully", log.Fields{"Device": device, "Vnet": vv.Name})
2996 } else {
2997 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "PendingDelFlows": vv.PendingDeleteFlow[device]})
2998 }
2999 vv.VnetPortLock.RUnlock()
3000}
3001
3002//FlowRemoveSuccess - Process flow success indication
3003func (vv *VoltVnet) FlowRemoveSuccess(cookie string, device string) {
3004 vv.VnetLock.Lock()
3005 defer vv.VnetLock.Unlock()
3006
3007 logger.Infow(ctx, "Vnet Flow Remove Success Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device})
3008
3009 if _, ok := vv.PendingDeleteFlow[device]; ok {
3010 delete(vv.PendingDeleteFlow[device], cookie)
3011 }
3012
3013 //Check and update success for pending disable request
3014 if d := GetApplication().GetDevice(device); d != nil {
3015 _, present := d.ConfiguredVlanForDeviceFlows.Get(VnetKey(vv.SVlan, vv.CVlan, 0))
3016 if !present && len(vv.PendingDeleteFlow[device]) == 0 {
3017 vv.CheckAndDeleteVnet(device)
3018 }
3019 }
3020 vv.WriteToDb()
3021}
3022
3023//FlowRemoveFailure - Process flow failure indication
3024func (vv *VoltVnet) FlowRemoveFailure(cookie string, device string, errorCode uint32, errReason string) {
3025
3026 vv.VnetLock.Lock()
3027 defer vv.VnetLock.Unlock()
3028
3029 if flowMap, ok := vv.PendingDeleteFlow[device]; ok {
3030 if _, ok := flowMap[cookie]; ok {
3031 logger.Errorw(ctx, "Device Flow Remove Failure Notification", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
3032
3033 if vv.DeleteInProgress {
3034 delete(vv.PendingDeleteFlow[device], cookie)
3035 vv.CheckAndDeleteVnet(device)
3036 }
3037 return
3038 }
3039 }
3040 logger.Errorw(ctx, "Device Flow Remove Failure Notification for Unknown cookie", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3041}
3042
3043//IgmpFlowInstallFailure - Process flow failure indication and triggers HSIA failure for Igmp enabled services
3044func (vpv *VoltPortVnet) IgmpFlowInstallFailure(cookie string, errorCode uint32, errReason string) {
3045
3046 //Note: Current implementation supports only for single service with Igmp Enabled for a subscriber
3047 //When multiple Igmp-suported service enabled, comment "return false"
3048
3049 sendFlowFailureInd := func(key, value interface{}) bool {
3050 svc := value.(*VoltService)
3051 if svc.IgmpEnabled {
3052 svc.triggerServiceFailureInd(errorCode, errReason)
3053 return false
3054 }
3055 return true
3056 }
3057 logger.Errorw(ctx, "US IGMP Flow Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3058 vpv.services.Range(sendFlowFailureInd)
3059}
3060
3061// GetMatchingMcastService to get matching multicast service
3062func (va *VoltApplication) GetMatchingMcastService(port string, device string, cvlan of.VlanType) *VoltService {
3063
3064 var service *VoltService
3065 dIntf, ok := va.DevicesDisc.Load(device)
3066 if !ok {
3067 return nil
3068 }
3069 d := dIntf.(*VoltDevice)
3070
3071 // If the port is NNI port, the services dont exist on it. The svc then
3072 // must be obtained from a different context and is not included here
3073 if port == d.NniPort {
3074 return nil
3075 }
3076
3077 // This is an access port and the port should have all the associated
3078 // services which can be uniquely identified by the VLANs in the packet
3079 vnets, ok := va.VnetsByPort.Load(port)
3080
3081 if !ok {
3082 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
3083 return nil
3084 }
3085 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": cvlan})
3086 getMcastService := func(key, value interface{}) bool {
3087 srv := value.(*VoltService)
3088 if srv.IgmpEnabled {
3089 service = srv
3090
3091 //TODO: Current implementation supports only for single service with Igmp Enabled
3092 //FIX-ME: When multiple service suports Igmp, update of logic required
3093 return false
3094 }
3095 return true
3096 }
3097
3098 for _, vpv := range vnets.([]*VoltPortVnet) {
3099 if vpv.CVlan == cvlan {
3100 vpv.services.Range(getMcastService)
3101 if service != nil {
3102 break
3103 }
3104 }
3105 }
3106 return service
3107}
3108
3109//TriggerAssociatedFlowDelete - Re-trigger delete for pending delete flows
3110func (vv *VoltVnet) TriggerAssociatedFlowDelete(device string) bool {
3111 vv.VnetLock.Lock()
3112 cookieList := []uint64{}
3113 flowMap := vv.PendingDeleteFlow[device]
3114
3115 for cookie := range flowMap {
3116 cookieList = append(cookieList, convertToUInt64(cookie))
3117 }
3118 vv.VnetLock.Unlock()
3119
3120 if len(cookieList) == 0 {
3121 return false
3122 }
3123
3124 for _, cookie := range cookieList {
3125 if vd := GetApplication().GetDevice(device); vd != nil {
3126 flow := &of.VoltFlow{}
3127 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3128 subFlow := of.NewVoltSubFlow()
3129 subFlow.Cookie = cookie
3130 flow.SubFlows[cookie] = subFlow
3131 logger.Infow(ctx, "Retriggering Vnet Delete Flow", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie})
3132 if err := vv.RemoveFlows(vd, flow); err != nil {
3133 logger.Warnw(ctx, "Vnet Delete Flow Failed", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie, "Error": err})
3134 }
3135 }
3136 }
3137 return true
3138}