blob: fd2e8c8426ae9fd0ca38cce713a63b5eb4dc90d6 [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"
Tinoj Joseph1d108322022-07-13 10:07:39 +053023 "voltha-go-controller/log"
vinokuma926cb3e2023-03-29 11:41:06 +053024
Naveen Sampath04696f72022-06-13 15:19:14 +053025 "github.com/opencord/voltha-protos/v5/go/common"
26 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
27)
28
29// AuditEventType type
30type AuditEventType uint8
31
32const (
33 // AuditEventDeviceDisc constant
34 AuditEventDeviceDisc AuditEventType = 0
35 // AuditEventDeviceStateChange constant
36 AuditEventDeviceStateChange AuditEventType = 1
37)
38
39const (
40 // NNIPortID NNI port id
41 NNIPortID uint32 = 0x1000000
42)
43
44// AuditDevice structure
45type AuditDevice struct {
Naveen Sampath04696f72022-06-13 15:19:14 +053046 ctx context.Context
47 device *Device
Naveen Sampath04696f72022-06-13 15:19:14 +053048 timestamp string
49 event AuditEventType
vinokuma926cb3e2023-03-29 11:41:06 +053050 taskID uint8
51 stop bool
Naveen Sampath04696f72022-06-13 15:19:14 +053052}
53
54// NewAuditDevice is constructor for AuditDevice
55func NewAuditDevice(device *Device, event AuditEventType) *AuditDevice {
56 var ad AuditDevice
57 ad.device = device
58 ad.stop = false
59 tstamp := (time.Now()).Format(time.RFC3339Nano)
60 ad.timestamp = tstamp
61 ad.event = event
62 return &ad
63}
64
65// Name returns the task name
66func (ad *AuditDevice) Name() string {
67 return "Device Audit Task"
68}
69
70// TaskID returns the task id
71func (ad *AuditDevice) TaskID() uint8 {
72 return ad.taskID
73}
74
75// Timestamp returns the timestamp for the task
76func (ad *AuditDevice) Timestamp() string {
77 return ad.timestamp
78}
79
80// Stop to stop the task
81func (ad *AuditDevice) Stop() {
82 ad.stop = true
83}
84
85// Start to start the task
86func (ad *AuditDevice) Start(ctx context.Context, taskID uint8) error {
Akash Soni6168f312023-05-18 20:57:33 +053087 logger.Infow(ctx, "Audit Device Task Triggered", log.Fields{"Context": ctx, "taskId": taskID, "Device": ad.device.ID})
Naveen Sampath04696f72022-06-13 15:19:14 +053088 ad.taskID = taskID
89 ad.ctx = ctx
90
91 if ad.stop {
vinokuma926cb3e2023-03-29 11:41:06 +053092 logger.Errorw(ctx, "Audit Device Task Canceled", log.Fields{"Context": ad.ctx, "Task": ad.taskID})
Naveen Sampath04696f72022-06-13 15:19:14 +053093 return tasks.ErrTaskCancelError
94 }
95
96 ofpps, err := ad.device.VolthaClient().ListLogicalDevicePorts(ad.ctx, &common.ID{Id: ad.device.ID})
97 if err != nil {
98 return err
99 }
100
101 // Compute the difference between the ports received and ports at VGC
102 // First build a map of all the received ports under missing ports. We
103 // will eliminate the ports that are in the device from the missing ports
104 // so that the elements remaining are missing ports. The ones that are
105 // not in missing ports are added to excess ports which should be deleted
106 // from the VGC.
107 missingPorts := make(map[uint32]*ofp.OfpPort)
108 for _, ofpp := range ofpps.Items {
109 missingPorts[ofpp.OfpPort.PortNo] = ofpp.OfpPort
Akash Soni6168f312023-05-18 20:57:33 +0530110 logger.Infow(ctx, "Missing Ports", log.Fields{"Ports": ofpp.OfpPort, "missingPorts": missingPorts})
Naveen Sampath04696f72022-06-13 15:19:14 +0530111 }
112
113 var excessPorts []uint32
114 GetController().SetAuditFlags(ad.device)
115
116 processPortState := func(id uint32, vgcPort *DevicePort) {
117 logger.Debugw(ctx, "Process Port State Ind", log.Fields{"Port No": vgcPort.ID, "Port Name": vgcPort.Name})
118
119 if ofpPort, ok := missingPorts[id]; ok {
120 if ((vgcPort.State == PortStateDown) && (ofpPort.State == uint32(ofp.OfpPortState_OFPPS_LIVE))) || ((vgcPort.State == PortStateUp) && (ofpPort.State != uint32(ofp.OfpPortState_OFPPS_LIVE))) {
121 // This port exists in the received list and the map at
122 // VGC. This is common so delete it
123 logger.Infow(ctx, "Port State Mismatch", log.Fields{"Port": vgcPort.ID, "OfpPort": ofpPort.PortNo, "ReceivedState": ofpPort.State, "CurrentState": vgcPort.State})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530124 ad.device.ProcessPortState(ctx, ofpPort.PortNo, ofpPort.State)
Naveen Sampath04696f72022-06-13 15:19:14 +0530125 } else {
126 //To ensure the flows are in sync with port status and no mismatch due to reboot,
127 // repush/delete flows based on current port status
128 logger.Infow(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 +0530129 ad.device.ProcessPortStateAfterReboot(ctx, ofpPort.PortNo, ofpPort.State)
Naveen Sampath04696f72022-06-13 15:19:14 +0530130 }
131 delete(missingPorts, id)
132 } else {
133 // This port is missing from the received list. This is an
134 // excess port at VGC. This must be added to excess ports
135 excessPorts = append(excessPorts, id)
136 }
137 logger.Debugw(ctx, "Processed Port State Ind", log.Fields{"Port No": vgcPort.ID, "Port Name": vgcPort.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530138 }
139
140 // 1st process the NNI port before all other ports so that the device state can be updated.
141 if vgcPort, ok := ad.device.PortsByID[NNIPortID]; ok {
Akash Soni6168f312023-05-18 20:57:33 +0530142 logger.Infow(ctx, "Processing NNI port state", log.Fields{"PortNo": vgcPort.ID, "PortName": vgcPort.Name, "PortState": vgcPort.State})
Naveen Sampath04696f72022-06-13 15:19:14 +0530143 processPortState(NNIPortID, vgcPort)
144 }
145
146 for id, vgcPort := range ad.device.PortsByID {
147 if id == NNIPortID {
148 //NNI port already processed
149 continue
150 }
151 if ad.stop {
152 break
153 }
154 processPortState(id, vgcPort)
155 }
156 GetController().ResetAuditFlags(ad.device)
157
158 if ad.stop {
vinokuma926cb3e2023-03-29 11:41:06 +0530159 logger.Errorw(ctx, "Audit Device Task Canceled", log.Fields{"Context": ad.ctx, "Task": ad.taskID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530160 return tasks.ErrTaskCancelError
161 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530162 ad.AddMissingPorts(ctx, missingPorts)
163 ad.DelExcessPorts(ctx, excessPorts)
Naveen Sampath04696f72022-06-13 15:19:14 +0530164 ad.device.deviceAuditInProgress = false
Akash Soni6168f312023-05-18 20:57:33 +0530165 logger.Infow(ctx, "Audit Device Task Completed", log.Fields{"Context": ctx, "taskId": taskID, "Device": ad.device.ID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530166 return nil
167}
168
169// AddMissingPorts to add the missing ports
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530170func (ad *AuditDevice) AddMissingPorts(cntx context.Context, mps map[uint32]*ofp.OfpPort) {
Akash Soni6168f312023-05-18 20:57:33 +0530171 logger.Infow(ctx, "Device Audit - Add Missing Ports", log.Fields{"NumPorts": len(mps), "Ports": mps})
Naveen Sampath04696f72022-06-13 15:19:14 +0530172
173 addMissingPort := func(mp *ofp.OfpPort) {
174 logger.Debugw(ctx, "Process Port Add Ind", log.Fields{"Port No": mp.PortNo, "Port Name": mp.Name})
175
176 // Error is ignored as it only drops duplicate ports
177 logger.Infow(ctx, "Calling AddPort", log.Fields{"No": mp.PortNo, "Name": mp.Name})
Tinoj Joseph429b9d92022-11-16 18:51:05 +0530178 if err := ad.device.AddPort(cntx, mp); err != nil {
Akash Soni6168f312023-05-18 20:57:33 +0530179 logger.Warnw(ctx, "AddPort Failed", log.Fields{"Port No": mp.PortNo, "Port Name": mp.Name, "Reason": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530180 }
181 if mp.State == uint32(ofp.OfpPortState_OFPPS_LIVE) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530182 ad.device.ProcessPortState(cntx, mp.PortNo, mp.State)
Naveen Sampath04696f72022-06-13 15:19:14 +0530183 }
184 logger.Debugw(ctx, "Processed Port Add Ind", log.Fields{"Port No": mp.PortNo, "Port Name": mp.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530185 }
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 {
Akash Soni6168f312023-05-18 20:57:33 +0530189 logger.Debugw(ctx, "Adding Missing NNI port", log.Fields{"PortNo": mp.PortNo, "Port Name": mp.Name, "Port Status": mp.State})
Naveen Sampath04696f72022-06-13 15:19:14 +0530190 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
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530201func (ad *AuditDevice) DelExcessPorts(cntx context.Context, eps []uint32) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530202 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})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530206 if err := ad.device.DelPort(cntx, id); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530207 logger.Warnw(ctx, "DelPort Failed", log.Fields{"PortId": id, "Reason": err})
208 }
209 }
210}