blob: 2cabffc5a1e9fff52809e334070a2fb9d9ba254b [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 controller
17
18import (
19 "context"
20 "time"
21
22 "voltha-go-controller/internal/pkg/tasks"
Tinoj Joseph1d108322022-07-13 10:07:39 +053023 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053024 "github.com/opencord/voltha-protos/v5/go/common"
25 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
26)
27
28// AuditEventType type
29type AuditEventType uint8
30
31const (
32 // AuditEventDeviceDisc constant
33 AuditEventDeviceDisc AuditEventType = 0
34 // AuditEventDeviceStateChange constant
35 AuditEventDeviceStateChange AuditEventType = 1
36)
37
38const (
39 // NNIPortID NNI port id
40 NNIPortID uint32 = 0x1000000
41)
42
43// AuditDevice structure
44type AuditDevice struct {
45 taskID uint8
46 ctx context.Context
47 device *Device
48 stop bool
49 timestamp string
50 event AuditEventType
51}
52
53// NewAuditDevice is constructor for AuditDevice
54func NewAuditDevice(device *Device, event AuditEventType) *AuditDevice {
55 var ad AuditDevice
56 ad.device = device
57 ad.stop = false
58 tstamp := (time.Now()).Format(time.RFC3339Nano)
59 ad.timestamp = tstamp
60 ad.event = event
61 return &ad
62}
63
64// Name returns the task name
65func (ad *AuditDevice) Name() string {
66 return "Device Audit Task"
67}
68
69// TaskID returns the task id
70func (ad *AuditDevice) TaskID() uint8 {
71 return ad.taskID
72}
73
74// Timestamp returns the timestamp for the task
75func (ad *AuditDevice) Timestamp() string {
76 return ad.timestamp
77}
78
79// Stop to stop the task
80func (ad *AuditDevice) Stop() {
81 ad.stop = true
82}
83
84// Start to start the task
85func (ad *AuditDevice) Start(ctx context.Context, taskID uint8) error {
86 logger.Warnw(ctx, "Audit Device Task Triggered", log.Fields{"Context": ctx, "taskId": taskID, "Device": ad.device.ID})
87 ad.taskID = taskID
88 ad.ctx = ctx
89
90 if ad.stop {
91 logger.Errorw(ctx, "Audit Device Task Cancelled", log.Fields{"Context": ad.ctx, "Task": ad.taskID})
92 return tasks.ErrTaskCancelError
93 }
94
95 ofpps, err := ad.device.VolthaClient().ListLogicalDevicePorts(ad.ctx, &common.ID{Id: ad.device.ID})
96 if err != nil {
97 return err
98 }
99
100 // Compute the difference between the ports received and ports at VGC
101 // First build a map of all the received ports under missing ports. We
102 // will eliminate the ports that are in the device from the missing ports
103 // so that the elements remaining are missing ports. The ones that are
104 // not in missing ports are added to excess ports which should be deleted
105 // from the VGC.
106 missingPorts := make(map[uint32]*ofp.OfpPort)
107 for _, ofpp := range ofpps.Items {
108 missingPorts[ofpp.OfpPort.PortNo] = ofpp.OfpPort
109 }
110
111 var excessPorts []uint32
112 GetController().SetAuditFlags(ad.device)
113
114 processPortState := func(id uint32, vgcPort *DevicePort) {
115 logger.Debugw(ctx, "Process Port State Ind", log.Fields{"Port No": vgcPort.ID, "Port Name": vgcPort.Name})
116
117 if ofpPort, ok := missingPorts[id]; ok {
118 if ((vgcPort.State == PortStateDown) && (ofpPort.State == uint32(ofp.OfpPortState_OFPPS_LIVE))) || ((vgcPort.State == PortStateUp) && (ofpPort.State != uint32(ofp.OfpPortState_OFPPS_LIVE))) {
119 // This port exists in the received list and the map at
120 // VGC. This is common so delete it
121 logger.Infow(ctx, "Port State Mismatch", log.Fields{"Port": vgcPort.ID, "OfpPort": ofpPort.PortNo, "ReceivedState": ofpPort.State, "CurrentState": vgcPort.State})
122 ad.device.ProcessPortState(ofpPort.PortNo, ofpPort.State)
123 } else {
124 //To ensure the flows are in sync with port status and no mismatch due to reboot,
125 // repush/delete flows based on current port status
126 logger.Infow(ctx, "Port State Processing", log.Fields{"Port": vgcPort.ID, "OfpPort": ofpPort.PortNo, "ReceivedState": ofpPort.State, "CurrentState": vgcPort.State})
127 ad.device.ProcessPortStateAfterReboot(ofpPort.PortNo, ofpPort.State)
128 }
129 delete(missingPorts, id)
130 } else {
131 // This port is missing from the received list. This is an
132 // excess port at VGC. This must be added to excess ports
133 excessPorts = append(excessPorts, id)
134 }
135 logger.Debugw(ctx, "Processed Port State Ind", log.Fields{"Port No": vgcPort.ID, "Port Name": vgcPort.Name})
136
137 }
138
139 // 1st process the NNI port before all other ports so that the device state can be updated.
140 if vgcPort, ok := ad.device.PortsByID[NNIPortID]; ok {
141 logger.Info(ctx, "Processing NNI port state")
142 processPortState(NNIPortID, vgcPort)
143 }
144
145 for id, vgcPort := range ad.device.PortsByID {
146 if id == NNIPortID {
147 //NNI port already processed
148 continue
149 }
150 if ad.stop {
151 break
152 }
153 processPortState(id, vgcPort)
154 }
155 GetController().ResetAuditFlags(ad.device)
156
157 if ad.stop {
158 logger.Errorw(ctx, "Audit Device Task Cancelled", log.Fields{"Context": ad.ctx, "Task": ad.taskID})
159 return tasks.ErrTaskCancelError
160 }
161 ad.AddMissingPorts(missingPorts)
162 ad.DelExcessPorts(excessPorts)
163 ad.device.deviceAuditInProgress = false
164 logger.Warnw(ctx, "Audit Device Task Completed", log.Fields{"Context": ctx, "taskId": taskID, "Device": ad.device.ID})
165 return nil
166}
167
168// AddMissingPorts to add the missing ports
169func (ad *AuditDevice) AddMissingPorts(mps map[uint32]*ofp.OfpPort) {
170 logger.Debugw(ctx, "Device Audit - Add Missing Ports", log.Fields{"NumPorts": len(mps)})
171
172 addMissingPort := func(mp *ofp.OfpPort) {
173 logger.Debugw(ctx, "Process Port Add Ind", log.Fields{"Port No": mp.PortNo, "Port Name": mp.Name})
174
175 // Error is ignored as it only drops duplicate ports
176 logger.Infow(ctx, "Calling AddPort", log.Fields{"No": mp.PortNo, "Name": mp.Name})
177 if err := ad.device.AddPort(mp.PortNo, mp.Name); err != nil {
178 logger.Warnw(ctx, "AddPort Failed", log.Fields{"No": mp.PortNo, "Name": mp.Name, "Reason": err})
179 }
180 if mp.State == uint32(ofp.OfpPortState_OFPPS_LIVE) {
181 ad.device.ProcessPortState(mp.PortNo, mp.State)
182 }
183 logger.Debugw(ctx, "Processed Port Add Ind", log.Fields{"Port No": mp.PortNo, "Port Name": mp.Name})
184
185 }
186
187 // 1st process the NNI port before all other ports so that the flow provisioning for UNIs can be enabled
188 if mp, ok := mps[NNIPortID]; ok {
189 logger.Info(ctx, "Adding Missing NNI port")
190 addMissingPort(mp)
191 }
192
193 for portNo, mp := range mps {
194 if portNo != NNIPortID {
195 addMissingPort(mp)
196 }
197 }
198}
199
200// DelExcessPorts to delete the excess ports
201func (ad *AuditDevice) DelExcessPorts(eps []uint32) {
202 logger.Debugw(ctx, "Device Audit - Delete Excess Ports", log.Fields{"NumPorts": len(eps)})
203 for _, id := range eps {
204 // Now delete the port from the device @ VGC
205 logger.Infow(ctx, "Device Audit - Deleting Port", log.Fields{"PortId": id})
206 if err := ad.device.DelPort(id); err != nil {
207 logger.Warnw(ctx, "DelPort Failed", log.Fields{"PortId": id, "Reason": err})
208 }
209 }
210}