blob: 69dfd78fc148695c952568c9e6c7701805a3c0a3 [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
npujar1d86a522019-11-14 17:11:16 +053016
khenaidoob9203542018-09-17 22:56:37 -040017package core
18
19import (
npujar467fe752020-01-16 20:17:45 +053020 "context"
npujar1d86a522019-11-14 17:11:16 +053021 "github.com/opencord/voltha-go/rw_core/coreif"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080022 "github.com/opencord/voltha-lib-go/v3/pkg/log"
23 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040024)
25
npujar1d86a522019-11-14 17:11:16 +053026// DeviceType mentions type of device like parent, child
khenaidoob9203542018-09-17 22:56:37 -040027type DeviceType int32
28
29const (
30 parent DeviceType = 0
31 child DeviceType = 1
32 any DeviceType = 2
33)
34
khenaidoo442e7c72020-03-10 16:13:48 -040035type MatchResult uint8
36
37const (
38 noMatch MatchResult = iota // current state has not match in the transition table
39 currWildcardMatch // current state matches the wildcard *_UNKNOWN state in the transition table
40 currStateOnlyMatch // current state matches the current state and previous state matches the wildcard in the transition table
41 currPrevStateMatch // both current and previous states match in the transition table
42)
43
44// match is used to keep the current match states
45type match struct {
46 admin, oper, conn MatchResult
47}
48
49// toInt returns an integer representing the matching level of the match (the larger the number the better)
50func (m *match) toInt() int {
51 return int(m.admin<<4 | m.oper<<2 | m.conn)
52}
53
54// isExactMatch returns true if match is an exact match
55func (m *match) isExactMatch() bool {
56 return m.admin == currPrevStateMatch && m.oper == currPrevStateMatch && m.conn == currPrevStateMatch
57}
58
59// isBetterMatch returns true if newMatch is a worse match
60func (m *match) isBetterMatch(newMatch *match) bool {
61 return m.toInt() > newMatch.toInt()
62}
63
npujar1d86a522019-11-14 17:11:16 +053064// DeviceState has admin, operational and connection status of device
khenaidoob9203542018-09-17 22:56:37 -040065type DeviceState struct {
serkant.uluderya2ae470f2020-01-21 11:13:09 -080066 Admin voltha.AdminState_Types
67 Connection voltha.ConnectStatus_Types
68 Operational voltha.OperStatus_Types
khenaidoob9203542018-09-17 22:56:37 -040069}
70
khenaidoo442e7c72020-03-10 16:13:48 -040071// TransitionHandler function type which takes the current and previous device info as input parameter
72type TransitionHandler func(ctx context.Context, curr *voltha.Device, prev *voltha.Device) error
khenaidoob9203542018-09-17 22:56:37 -040073
npujar1d86a522019-11-14 17:11:16 +053074// Transition represent transition related attributes
khenaidoob9203542018-09-17 22:56:37 -040075type Transition struct {
76 deviceType DeviceType
77 previousState DeviceState
78 currentState DeviceState
khenaidoo92e62c52018-10-03 14:02:54 -040079 handlers []TransitionHandler
khenaidoob9203542018-09-17 22:56:37 -040080}
81
npujar1d86a522019-11-14 17:11:16 +053082// TransitionMap represent map of transitions and device manager
khenaidoob9203542018-09-17 22:56:37 -040083type TransitionMap struct {
84 transitions []Transition
npujar1d86a522019-11-14 17:11:16 +053085 dMgr coreif.DeviceManager
khenaidoob9203542018-09-17 22:56:37 -040086}
87
npujar1d86a522019-11-14 17:11:16 +053088// NewTransitionMap creates transition map
89func NewTransitionMap(dMgr coreif.DeviceManager) *TransitionMap {
khenaidoob9203542018-09-17 22:56:37 -040090 var transitionMap TransitionMap
khenaidoo0a822f92019-05-08 15:15:57 -040091 transitionMap.dMgr = dMgr
khenaidoob9203542018-09-17 22:56:37 -040092 transitionMap.transitions = make([]Transition, 0)
khenaidoo442e7c72020-03-10 16:13:48 -040093 transitionMap.transitions = append(
94 transitionMap.transitions,
khenaidoob9203542018-09-17 22:56:37 -040095 Transition{
khenaidoob9203542018-09-17 22:56:37 -040096 deviceType: parent,
khenaidoo59ef7be2019-06-21 12:40:28 -040097 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVATING},
98 currentState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVE},
khenaidoo0a822f92019-05-08 15:15:57 -040099 handlers: []TransitionHandler{dMgr.CreateLogicalDevice}})
100 transitionMap.transitions = append(transitionMap.transitions,
101 Transition{
khenaidoo59ef7be2019-06-21 12:40:28 -0400102 deviceType: child,
103 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_DISCOVERED},
khenaidoo442e7c72020-03-10 16:13:48 -0400104 currentState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVATING},
105 handlers: []TransitionHandler{}})
106 transitionMap.transitions = append(transitionMap.transitions,
107 Transition{
108 deviceType: child,
109 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_DISCOVERED},
khenaidoo59ef7be2019-06-21 12:40:28 -0400110 currentState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVE},
111 handlers: []TransitionHandler{dMgr.SetupUNILogicalPorts}})
khenaidoob9203542018-09-17 22:56:37 -0400112 transitionMap.transitions = append(transitionMap.transitions,
113 Transition{
114 deviceType: child,
khenaidoo59ef7be2019-06-21 12:40:28 -0400115 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVATING},
khenaidoo442e7c72020-03-10 16:13:48 -0400116 currentState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_DISCOVERED},
117 handlers: []TransitionHandler{}})
118 transitionMap.transitions = append(transitionMap.transitions,
119 Transition{
120 deviceType: child,
121 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVATING},
khenaidoo59ef7be2019-06-21 12:40:28 -0400122 currentState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVE},
khenaidoo0a822f92019-05-08 15:15:57 -0400123 handlers: []TransitionHandler{dMgr.SetupUNILogicalPorts}})
khenaidoob9203542018-09-17 22:56:37 -0400124 transitionMap.transitions = append(transitionMap.transitions,
125 Transition{
khenaidoo4554f7c2019-05-29 22:13:15 -0400126 deviceType: any,
127 previousState: DeviceState{Admin: voltha.AdminState_PREPROVISIONED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
128 currentState: DeviceState{Admin: voltha.AdminState_DELETED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
129 handlers: []TransitionHandler{dMgr.RunPostDeviceDelete}})
130 transitionMap.transitions = append(transitionMap.transitions,
131 Transition{
khenaidoo4d4802d2018-10-04 21:59:49 -0400132 deviceType: parent,
khenaidoo442e7c72020-03-10 16:13:48 -0400133 previousState: DeviceState{Admin: voltha.AdminState_UNKNOWN, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
khenaidoo4d4802d2018-10-04 21:59:49 -0400134 currentState: DeviceState{Admin: voltha.AdminState_DELETED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
Hardik Windlassc704def2020-02-26 18:23:19 +0000135 handlers: []TransitionHandler{dMgr.DisableAllChildDevices, dMgr.DeleteAllUNILogicalPorts, dMgr.DeleteAllChildDevices, dMgr.DeleteLogicalDevice, dMgr.RunPostDeviceDelete}})
khenaidoo0a822f92019-05-08 15:15:57 -0400136 transitionMap.transitions = append(transitionMap.transitions,
137 Transition{
138 deviceType: child,
khenaidoo442e7c72020-03-10 16:13:48 -0400139 previousState: DeviceState{Admin: voltha.AdminState_UNKNOWN, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
khenaidoo0a822f92019-05-08 15:15:57 -0400140 currentState: DeviceState{Admin: voltha.AdminState_DELETED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
Chaitrashree G S543df3e2020-02-24 22:36:54 -0500141 handlers: []TransitionHandler{dMgr.ChildDeviceLost, dMgr.DeleteLogicalPorts, dMgr.RunPostDeviceDelete}})
142 transitionMap.transitions = append(transitionMap.transitions,
143 Transition{
144 deviceType: child,
145 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
146 currentState: DeviceState{Admin: voltha.AdminState_DELETED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
147 handlers: []TransitionHandler{dMgr.ChildDeviceLost, dMgr.DeleteLogicalPorts, dMgr.RunPostDeviceDelete}})
khenaidoob9203542018-09-17 22:56:37 -0400148 transitionMap.transitions = append(transitionMap.transitions,
149 Transition{
150 deviceType: any,
khenaidoo59ef7be2019-06-21 12:40:28 -0400151 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVE},
152 currentState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVATING},
153 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
154 transitionMap.transitions = append(transitionMap.transitions,
155 Transition{
156 deviceType: any,
157 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVATING},
158 currentState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
159 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
160 transitionMap.transitions = append(transitionMap.transitions,
161 Transition{
162 deviceType: any,
163 previousState: DeviceState{Admin: voltha.AdminState_PREPROVISIONED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
164 currentState: DeviceState{Admin: voltha.AdminState_UNKNOWN, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
165 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
166 transitionMap.transitions = append(transitionMap.transitions,
167 Transition{
168 deviceType: any,
169 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
170 currentState: DeviceState{Admin: voltha.AdminState_DOWNLOADING_IMAGE, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
171 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
172 transitionMap.transitions = append(transitionMap.transitions,
173 Transition{
174 deviceType: any,
175 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
176 currentState: DeviceState{Admin: voltha.AdminState_UNKNOWN, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
177 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
178 transitionMap.transitions = append(transitionMap.transitions,
179 Transition{
180 deviceType: parent,
181 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVE},
182 currentState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVATING},
183 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
184 transitionMap.transitions = append(transitionMap.transitions,
185 Transition{
186 deviceType: any,
187 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_ACTIVATING},
188 currentState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
189 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
190 transitionMap.transitions = append(transitionMap.transitions,
191 Transition{
192 deviceType: any,
193 previousState: DeviceState{Admin: voltha.AdminState_ENABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
194 currentState: DeviceState{Admin: voltha.AdminState_PREPROVISIONED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
195 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
196 transitionMap.transitions = append(transitionMap.transitions,
197 Transition{
198 deviceType: child,
199 previousState: DeviceState{Admin: voltha.AdminState_DISABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
200 currentState: DeviceState{Admin: voltha.AdminState_UNKNOWN, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
201 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
202 transitionMap.transitions = append(transitionMap.transitions,
203 Transition{
204 deviceType: any,
205 previousState: DeviceState{Admin: voltha.AdminState_DISABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
206 currentState: DeviceState{Admin: voltha.AdminState_PREPROVISIONED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
207 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
208 transitionMap.transitions = append(transitionMap.transitions,
209 Transition{
210 deviceType: any,
khenaidoob9203542018-09-17 22:56:37 -0400211 previousState: DeviceState{Admin: voltha.AdminState_DOWNLOADING_IMAGE, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
212 currentState: DeviceState{Admin: voltha.AdminState_DISABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
khenaidoo0a822f92019-05-08 15:15:57 -0400213 handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
khenaidoob9203542018-09-17 22:56:37 -0400214
215 return &transitionMap
216}
217
218func getDeviceStates(device *voltha.Device) *DeviceState {
219 return &DeviceState{Admin: device.AdminState, Connection: device.ConnectStatus, Operational: device.OperStatus}
220}
221
222// isMatched matches a state transition. It returns whether there is a match and if there is whether it is an exact match
khenaidoo442e7c72020-03-10 16:13:48 -0400223func getHandler(previous *DeviceState, current *DeviceState, transition *Transition) ([]TransitionHandler, *match) {
224 m := &match{}
khenaidoob9203542018-09-17 22:56:37 -0400225 // Do we have an exact match?
226 if *previous == transition.previousState && *current == transition.currentState {
khenaidoo442e7c72020-03-10 16:13:48 -0400227 return transition.handlers, &match{admin: currPrevStateMatch, oper: currPrevStateMatch, conn: currPrevStateMatch}
khenaidoob9203542018-09-17 22:56:37 -0400228 }
khenaidoo0a822f92019-05-08 15:15:57 -0400229
khenaidoo442e7c72020-03-10 16:13:48 -0400230 // Do we have Admin state match?
231 if current.Admin == transition.currentState.Admin && transition.currentState.Admin != voltha.AdminState_UNKNOWN {
232 if previous.Admin == transition.previousState.Admin {
233 m.admin = currPrevStateMatch
234 } else if transition.previousState.Admin == voltha.AdminState_UNKNOWN {
235 m.admin = currStateOnlyMatch
236 }
237 } else if current.Admin == transition.currentState.Admin && transition.currentState.Admin == voltha.AdminState_UNKNOWN {
238 if previous.Admin == transition.previousState.Admin || transition.previousState.Admin == voltha.AdminState_UNKNOWN {
239 m.admin = currWildcardMatch
240 }
241 }
242 if m.admin == noMatch {
243 // invalid transition - need to match on current admin state
244 return nil, m
khenaidoo0a822f92019-05-08 15:15:57 -0400245 }
246
khenaidoo442e7c72020-03-10 16:13:48 -0400247 // Do we have an operational state match?
248 if current.Operational == transition.currentState.Operational && transition.previousState.Operational != voltha.OperStatus_UNKNOWN {
249 if previous.Operational == transition.previousState.Operational || transition.previousState.Operational == voltha.OperStatus_UNKNOWN {
250 m.oper = currPrevStateMatch
251 } else {
252 m.oper = currStateOnlyMatch
253 }
254 } else if current.Operational == transition.currentState.Operational && transition.previousState.Operational == voltha.OperStatus_UNKNOWN {
255 if previous.Operational == transition.previousState.Operational || transition.previousState.Operational == voltha.OperStatus_UNKNOWN {
256 m.oper = currWildcardMatch
khenaidoob9203542018-09-17 22:56:37 -0400257 }
258 }
khenaidoo442e7c72020-03-10 16:13:48 -0400259
260 // Do we have an connection state match?
261 if current.Connection == transition.currentState.Connection && transition.previousState.Connection != voltha.ConnectStatus_UNKNOWN {
262 if previous.Connection == transition.previousState.Connection || transition.previousState.Connection == voltha.ConnectStatus_UNKNOWN {
263 m.conn = currPrevStateMatch
264 } else {
265 m.conn = currStateOnlyMatch
266 }
267 } else if current.Connection == transition.currentState.Connection && transition.previousState.Connection == voltha.ConnectStatus_UNKNOWN {
268 if previous.Connection == transition.previousState.Connection || transition.previousState.Connection == voltha.ConnectStatus_UNKNOWN {
269 m.conn = currWildcardMatch
khenaidoob9203542018-09-17 22:56:37 -0400270 }
271 }
khenaidoo442e7c72020-03-10 16:13:48 -0400272
273 return transition.handlers, m
khenaidoob9203542018-09-17 22:56:37 -0400274}
275
npujar1d86a522019-11-14 17:11:16 +0530276// GetTransitionHandler returns transition handler
khenaidoo92e62c52018-10-03 14:02:54 -0400277func (tMap *TransitionMap) GetTransitionHandler(pDevice *voltha.Device, cDevice *voltha.Device) []TransitionHandler {
khenaidoob9203542018-09-17 22:56:37 -0400278 //1. Get the previous and current set of states
279 pState := getDeviceStates(pDevice)
280 cState := getDeviceStates(cDevice)
khenaidoo442e7c72020-03-10 16:13:48 -0400281
282 // Do nothing is there are no states change
283 if *pState == *cState {
284 return nil
285 }
286
khenaidoo92e62c52018-10-03 14:02:54 -0400287 //log.Infow("DeviceType", log.Fields{"device": pDevice})
khenaidoob9203542018-09-17 22:56:37 -0400288 deviceType := parent
289 if !pDevice.Root {
290 log.Info("device is child")
291 deviceType = child
292 }
293 log.Infof("deviceType:%d-deviceId:%s-previous:%v-current:%v", deviceType, pDevice.Id, pState, cState)
294
295 //2. Go over transition array to get the right transition
khenaidoo92e62c52018-10-03 14:02:54 -0400296 var currentMatch []TransitionHandler
297 var tempHandler []TransitionHandler
khenaidoo442e7c72020-03-10 16:13:48 -0400298 var m *match
299 bestMatch := &match{}
khenaidoob9203542018-09-17 22:56:37 -0400300 for _, aTransition := range tMap.transitions {
301 // consider transition only if it matches deviceType or is a wild card - any
302 if aTransition.deviceType != deviceType && aTransition.deviceType != any {
303 continue
304 }
khenaidoo442e7c72020-03-10 16:13:48 -0400305 tempHandler, m = getHandler(pState, cState, &aTransition)
khenaidoob9203542018-09-17 22:56:37 -0400306 if tempHandler != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400307 if m.isExactMatch() && aTransition.deviceType == deviceType {
khenaidoob9203542018-09-17 22:56:37 -0400308 return tempHandler
khenaidoo442e7c72020-03-10 16:13:48 -0400309 } else if m.isExactMatch() || m.isBetterMatch(bestMatch) {
khenaidoo0a822f92019-05-08 15:15:57 -0400310 currentMatch = tempHandler
khenaidoo442e7c72020-03-10 16:13:48 -0400311 bestMatch = m
khenaidoob9203542018-09-17 22:56:37 -0400312 }
313 }
314 }
315 return currentMatch
316}