blob: b322737cda0c007b49b5092c7c20fb99c06e530b [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 {
87 logger.Warnw(ctx, "Audit Device Task Triggered", log.Fields{"Context": ctx, "taskId": taskID, "Device": ad.device.ID})
88 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
110 }
111
112 var excessPorts []uint32
113 GetController().SetAuditFlags(ad.device)
114
115 processPortState := func(id uint32, vgcPort *DevicePort) {
116 logger.Debugw(ctx, "Process Port State Ind", log.Fields{"Port No": vgcPort.ID, "Port Name": vgcPort.Name})
117
118 if ofpPort, ok := missingPorts[id]; ok {
119 if ((vgcPort.State == PortStateDown) && (ofpPort.State == uint32(ofp.OfpPortState_OFPPS_LIVE))) || ((vgcPort.State == PortStateUp) && (ofpPort.State != uint32(ofp.OfpPortState_OFPPS_LIVE))) {
120 // This port exists in the received list and the map at
121 // VGC. This is common so delete it
122 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 +0530123 ad.device.ProcessPortState(ctx, ofpPort.PortNo, ofpPort.State)
Naveen Sampath04696f72022-06-13 15:19:14 +0530124 } else {
125 //To ensure the flows are in sync with port status and no mismatch due to reboot,
126 // repush/delete flows based on current port status
127 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 +0530128 ad.device.ProcessPortStateAfterReboot(ctx, ofpPort.PortNo, ofpPort.State)
Naveen Sampath04696f72022-06-13 15:19:14 +0530129 }
130 delete(missingPorts, id)
131 } else {
132 // This port is missing from the received list. This is an
133 // excess port at VGC. This must be added to excess ports
134 excessPorts = append(excessPorts, id)
135 }
136 logger.Debugw(ctx, "Processed Port State Ind", log.Fields{"Port No": vgcPort.ID, "Port Name": vgcPort.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530137 }
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 {
vinokuma926cb3e2023-03-29 11:41:06 +0530158 logger.Errorw(ctx, "Audit Device Task Canceled", log.Fields{"Context": ad.ctx, "Task": ad.taskID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530159 return tasks.ErrTaskCancelError
160 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530161 ad.AddMissingPorts(ctx, missingPorts)
162 ad.DelExcessPorts(ctx, excessPorts)
Naveen Sampath04696f72022-06-13 15:19:14 +0530163 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
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530169func (ad *AuditDevice) AddMissingPorts(cntx context.Context, mps map[uint32]*ofp.OfpPort) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530170 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})
Tinoj Joseph429b9d92022-11-16 18:51:05 +0530177 if err := ad.device.AddPort(cntx, mp); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530178 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) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530181 ad.device.ProcessPortState(cntx, mp.PortNo, mp.State)
Naveen Sampath04696f72022-06-13 15:19:14 +0530182 }
183 logger.Debugw(ctx, "Processed Port Add Ind", log.Fields{"Port No": mp.PortNo, "Port Name": mp.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530184 }
185
186 // 1st process the NNI port before all other ports so that the flow provisioning for UNIs can be enabled
187 if mp, ok := mps[NNIPortID]; ok {
188 logger.Info(ctx, "Adding Missing NNI port")
189 addMissingPort(mp)
190 }
191
192 for portNo, mp := range mps {
193 if portNo != NNIPortID {
194 addMissingPort(mp)
195 }
196 }
197}
198
199// DelExcessPorts to delete the excess ports
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530200func (ad *AuditDevice) DelExcessPorts(cntx context.Context, eps []uint32) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530201 logger.Debugw(ctx, "Device Audit - Delete Excess Ports", log.Fields{"NumPorts": len(eps)})
202 for _, id := range eps {
203 // Now delete the port from the device @ VGC
204 logger.Infow(ctx, "Device Audit - Deleting Port", log.Fields{"PortId": id})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530205 if err := ad.device.DelPort(cntx, id); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530206 logger.Warnw(ctx, "DelPort Failed", log.Fields{"PortId": id, "Reason": err})
207 }
208 }
209}