blob: 37a9837626f28be42137cd5b8790650e4d147ce4 [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.
vinokuma926cb3e2023-03-29 11:41:06 +053014 */
Naveen Sampath04696f72022-06-13 15:19:14 +053015
16package controller
17
18import (
19 "context"
20 "time"
21
22 "voltha-go-controller/internal/pkg/tasks"
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +053023 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053024 "voltha-go-controller/log"
vinokuma926cb3e2023-03-29 11:41:06 +053025
Naveen Sampath04696f72022-06-13 15:19:14 +053026 "github.com/opencord/voltha-protos/v5/go/common"
27 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
28)
29
30// AuditEventType type
31type AuditEventType uint8
32
33const (
34 // AuditEventDeviceDisc constant
35 AuditEventDeviceDisc AuditEventType = 0
36 // AuditEventDeviceStateChange constant
37 AuditEventDeviceStateChange AuditEventType = 1
38)
39
40const (
41 // NNIPortID NNI port id
42 NNIPortID uint32 = 0x1000000
43)
44
45// AuditDevice structure
46type AuditDevice struct {
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +053047 ctx context.Context
48 device *Device
49 timestamp string
50 event AuditEventType
51 taskID uint8
52 stop bool
53 skipFlowOnRestart bool
Naveen Sampath04696f72022-06-13 15:19:14 +053054}
55
56// NewAuditDevice is constructor for AuditDevice
57func NewAuditDevice(device *Device, event AuditEventType) *AuditDevice {
58 var ad AuditDevice
59 ad.device = device
60 ad.stop = false
61 tstamp := (time.Now()).Format(time.RFC3339Nano)
62 ad.timestamp = tstamp
63 ad.event = event
64 return &ad
65}
66
67// Name returns the task name
68func (ad *AuditDevice) Name() string {
69 return "Device Audit Task"
70}
71
72// TaskID returns the task id
73func (ad *AuditDevice) TaskID() uint8 {
74 return ad.taskID
75}
76
77// Timestamp returns the timestamp for the task
78func (ad *AuditDevice) Timestamp() string {
79 return ad.timestamp
80}
81
82// Stop to stop the task
83func (ad *AuditDevice) Stop() {
84 ad.stop = true
85}
86
87// Start to start the task
88func (ad *AuditDevice) Start(ctx context.Context, taskID uint8) error {
Akash Sonie863fe42023-11-30 14:35:01 +053089 logger.Debugw(ctx, "Audit Device Task Triggered", log.Fields{"Context": ctx, "taskId": taskID, "Device": ad.device.ID})
Naveen Sampath04696f72022-06-13 15:19:14 +053090 ad.taskID = taskID
91 ad.ctx = ctx
92
93 if ad.stop {
vinokuma926cb3e2023-03-29 11:41:06 +053094 logger.Errorw(ctx, "Audit Device Task Canceled", log.Fields{"Context": ad.ctx, "Task": ad.taskID})
Naveen Sampath04696f72022-06-13 15:19:14 +053095 return tasks.ErrTaskCancelError
96 }
97
98 ofpps, err := ad.device.VolthaClient().ListLogicalDevicePorts(ad.ctx, &common.ID{Id: ad.device.ID})
99 if err != nil {
100 return err
101 }
102
103 // Compute the difference between the ports received and ports at VGC
104 // First build a map of all the received ports under missing ports. We
105 // will eliminate the ports that are in the device from the missing ports
106 // so that the elements remaining are missing ports. The ones that are
107 // not in missing ports are added to excess ports which should be deleted
108 // from the VGC.
109 missingPorts := make(map[uint32]*ofp.OfpPort)
110 for _, ofpp := range ofpps.Items {
111 missingPorts[ofpp.OfpPort.PortNo] = ofpp.OfpPort
112 }
113
Sridhar Ravindra0bc5dc52023-12-13 19:03:30 +0530114 excessPorts := make(map[uint32]*DevicePort)
Naveen Sampath04696f72022-06-13 15:19:14 +0530115 GetController().SetAuditFlags(ad.device)
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530116 defer GetController().ResetAuditFlags(ad.device)
Naveen Sampath04696f72022-06-13 15:19:14 +0530117
118 processPortState := func(id uint32, vgcPort *DevicePort) {
119 logger.Debugw(ctx, "Process Port State Ind", log.Fields{"Port No": vgcPort.ID, "Port Name": vgcPort.Name})
120
121 if ofpPort, ok := missingPorts[id]; ok {
122 if ((vgcPort.State == PortStateDown) && (ofpPort.State == uint32(ofp.OfpPortState_OFPPS_LIVE))) || ((vgcPort.State == PortStateUp) && (ofpPort.State != uint32(ofp.OfpPortState_OFPPS_LIVE))) {
123 // This port exists in the received list and the map at
124 // VGC. This is common so delete it
125 logger.Infow(ctx, "Port State Mismatch", log.Fields{"Port": vgcPort.ID, "OfpPort": ofpPort.PortNo, "ReceivedState": ofpPort.State, "CurrentState": vgcPort.State})
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530126 ad.device.ProcessPortState(ctx, ofpPort.PortNo, ofpPort.State, ofpPort.Name, ad.skipFlowOnRestart)
Naveen Sampath04696f72022-06-13 15:19:14 +0530127 } else {
128 //To ensure the flows are in sync with port status and no mismatch due to reboot,
129 // repush/delete flows based on current port status
Akash Sonie863fe42023-11-30 14:35:01 +0530130 logger.Debugw(ctx, "Port State Processing", log.Fields{"Port": vgcPort.ID, "OfpPort": ofpPort.PortNo, "ReceivedState": ofpPort.State, "CurrentState": vgcPort.State})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530131 ad.device.ProcessPortStateAfterReboot(ctx, ofpPort.PortNo, ofpPort.State)
Naveen Sampath04696f72022-06-13 15:19:14 +0530132 }
133 delete(missingPorts, id)
134 } else {
135 // This port is missing from the received list. This is an
136 // excess port at VGC. This must be added to excess ports
Sridhar Ravindra0bc5dc52023-12-13 19:03:30 +0530137 excessPorts[id] = vgcPort
Naveen Sampath04696f72022-06-13 15:19:14 +0530138 }
139 logger.Debugw(ctx, "Processed Port State Ind", log.Fields{"Port No": vgcPort.ID, "Port Name": vgcPort.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530140 }
141
142 // 1st process the NNI port before all other ports so that the device state can be updated.
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530143 for id, vgcPort := range ad.device.PortsByID {
144 if util.IsNniPort(id) {
145 logger.Debugw(ctx, "Processing NNI port state", log.Fields{"PortNo": vgcPort.ID, "PortName": vgcPort.Name, "PortState": vgcPort.State})
146 processPortState(id, vgcPort)
147 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530148 }
149
150 for id, vgcPort := range ad.device.PortsByID {
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530151 if util.IsNniPort(id) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530152 //NNI port already processed
153 continue
154 }
155 if ad.stop {
156 break
157 }
158 processPortState(id, vgcPort)
159 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530160
161 if ad.stop {
vinokuma926cb3e2023-03-29 11:41:06 +0530162 logger.Errorw(ctx, "Audit Device Task Canceled", log.Fields{"Context": ad.ctx, "Task": ad.taskID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530163 return tasks.ErrTaskCancelError
164 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530165 ad.AddMissingPorts(ctx, missingPorts)
166 ad.DelExcessPorts(ctx, excessPorts)
Naveen Sampath04696f72022-06-13 15:19:14 +0530167 ad.device.deviceAuditInProgress = false
Akash Sonie863fe42023-11-30 14:35:01 +0530168 logger.Debugw(ctx, "Audit Device Task Completed", log.Fields{"Context": ctx, "taskId": taskID, "Device": ad.device.ID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530169 return nil
170}
171
172// AddMissingPorts to add the missing ports
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530173func (ad *AuditDevice) AddMissingPorts(cntx context.Context, mps map[uint32]*ofp.OfpPort) {
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530174 logger.Debugw(ctx, "Device Audit - Add Missing Ports", log.Fields{"NumPorts": len(mps), "Ports": mps})
Naveen Sampath04696f72022-06-13 15:19:14 +0530175
176 addMissingPort := func(mp *ofp.OfpPort) {
177 logger.Debugw(ctx, "Process Port Add Ind", log.Fields{"Port No": mp.PortNo, "Port Name": mp.Name})
178
Tinoj Joseph429b9d92022-11-16 18:51:05 +0530179 if err := ad.device.AddPort(cntx, mp); err != nil {
Akash Soni6168f312023-05-18 20:57:33 +0530180 logger.Warnw(ctx, "AddPort Failed", log.Fields{"Port No": mp.PortNo, "Port Name": mp.Name, "Reason": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530181 }
182 if mp.State == uint32(ofp.OfpPortState_OFPPS_LIVE) {
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530183 ad.device.ProcessPortState(cntx, mp.PortNo, mp.State, mp.Name, ad.skipFlowOnRestart)
Naveen Sampath04696f72022-06-13 15:19:14 +0530184 }
185 logger.Debugw(ctx, "Processed Port Add Ind", log.Fields{"Port No": mp.PortNo, "Port Name": mp.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530186 }
187
188 // 1st process the NNI port before all other ports so that the flow provisioning for UNIs can be enabled
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530189 for portNo, mp := range mps {
190 if util.IsNniPort(portNo) {
191 logger.Debugw(ctx, "Adding Missing NNI port", log.Fields{"PortNo": mp.PortNo, "Port Name": mp.Name, "Port Status": mp.State})
192 addMissingPort(mp)
193 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530194 }
195
196 for portNo, mp := range mps {
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530197 if !util.IsNniPort(portNo) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530198 addMissingPort(mp)
199 }
200 }
201}
202
203// DelExcessPorts to delete the excess ports
Sridhar Ravindra0bc5dc52023-12-13 19:03:30 +0530204func (ad *AuditDevice) DelExcessPorts(cntx context.Context, eps map[uint32]*DevicePort) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530205 logger.Debugw(ctx, "Device Audit - Delete Excess Ports", log.Fields{"NumPorts": len(eps)})
Sridhar Ravindra0bc5dc52023-12-13 19:03:30 +0530206 for portNo, ep := range eps {
Naveen Sampath04696f72022-06-13 15:19:14 +0530207 // Now delete the port from the device @ VGC
Sridhar Ravindra0bc5dc52023-12-13 19:03:30 +0530208 logger.Debugw(ctx, "Device Audit - Deleting Port", log.Fields{"PortId": portNo})
209 if err := ad.device.DelPort(cntx, ep.ID, ep.Name); err != nil {
210 logger.Warnw(ctx, "DelPort Failed", log.Fields{"PortId": portNo, "Reason": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530211 }
212 }
213}