blob: c3d9ed21ed7bffe0d95f5cec77fa93e11a1ab078 [file] [log] [blame]
Girish Gowdru0c588b22019-04-23 23:24:56 -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 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070016
Scott Bakerdbd960e2020-02-28 08:57:51 -080017//Package core provides the utility for olt devices, flows and statistics
18package core
Girish Gowdru0c588b22019-04-23 23:24:56 -040019
20import (
npujarec5762e2020-01-01 14:08:48 +053021 "context"
Girish Gowdru0c588b22019-04-23 23:24:56 -040022 "reflect"
23 "runtime"
24
Girish Gowdraa09aeab2020-09-14 16:30:52 -070025 "github.com/opencord/voltha-lib-go/v4/pkg/log"
Girish Gowdru0c588b22019-04-23 23:24:56 -040026)
27
28// DeviceState OLT Device state
29type DeviceState int
30
31const (
32 // deviceStateNull OLT is not instantiated
33 deviceStateNull DeviceState = iota
34 // deviceStateInit OLT is instantiated
35 deviceStateInit
36 // deviceStateConnected Grpc session established with OLT
37 deviceStateConnected
38 // deviceStateUp Admin state of OLT is UP
39 deviceStateUp
40 // deviceStateDown Admin state of OLT is down
41 deviceStateDown
42)
43
Matteo Scandolo66fbaf52021-03-24 14:13:38 -070044func (d DeviceState) String() string {
45 names := [...]string{
46 "deviceStateNull",
47 "deviceStateInit",
48 "deviceStateConnected",
49 "deviceStateUp",
50 "deviceStateDown",
51 }
52 return names[d]
53}
54
Girish Gowdru0c588b22019-04-23 23:24:56 -040055// Trigger for changing the state
56type Trigger int
57
58const (
59 // DeviceInit Go to Device init state
60 DeviceInit Trigger = iota
61 // GrpcConnected Go to connected state
62 GrpcConnected
63 // DeviceUpInd Go to Device up state
64 DeviceUpInd
65 // DeviceDownInd Go to Device down state
66 DeviceDownInd
67 // GrpcDisconnected Go to Device init state
68 GrpcDisconnected
69)
70
71// TransitionHandler function type for handling transition
npujarec5762e2020-01-01 14:08:48 +053072type TransitionHandler func(ctx context.Context) error
Girish Gowdru0c588b22019-04-23 23:24:56 -040073
74// Transition to store state machine
75type Transition struct {
76 previousState []DeviceState
77 currentState DeviceState
78 before []TransitionHandler
79 after []TransitionHandler
80}
81
82// TransitionMap to store all the states and current device state
83type TransitionMap struct {
84 transitions map[Trigger]Transition
85 currentDeviceState DeviceState
86}
87
88// OpenoltDevice state machine:
89//
90// null ----> init ------> connected -----> up -----> down
91// ^ ^ | ^ | |
92// | | | | | |
93// | +-------------+ +---------+ |
94// | |
95// +-----------------------------------------+
96
97// NewTransitionMap create a new state machine with all the transitions
98func NewTransitionMap(dh *DeviceHandler) *TransitionMap {
99 var transitionMap TransitionMap
100 transitionMap.currentDeviceState = deviceStateNull
101 transitionMap.transitions = make(map[Trigger]Transition)
102 // In doInit establish the grpc session
103 transitionMap.transitions[DeviceInit] =
104 Transition{
Chaitrashree G Sa4649252020-03-11 21:24:11 -0400105 previousState: []DeviceState{deviceStateNull, deviceStateUp, deviceStateDown},
Girish Gowdru0c588b22019-04-23 23:24:56 -0400106 currentState: deviceStateInit,
107 before: []TransitionHandler{dh.doStateInit},
108 after: []TransitionHandler{dh.postInit}}
109 // If gRpc session fails, re-establish the grpc session
110 transitionMap.transitions[GrpcDisconnected] =
111 Transition{
112 previousState: []DeviceState{deviceStateConnected, deviceStateDown},
113 currentState: deviceStateInit,
114 before: []TransitionHandler{dh.doStateInit},
115 after: []TransitionHandler{dh.postInit}}
116 // in doConnected, create logical device and read the indications
117 transitionMap.transitions[GrpcConnected] =
118 Transition{
119 previousState: []DeviceState{deviceStateInit},
120 currentState: deviceStateConnected,
121 before: []TransitionHandler{dh.doStateConnected}}
122
123 // Once the olt UP is indication received, then do state up
124 transitionMap.transitions[DeviceUpInd] =
125 Transition{
126 previousState: []DeviceState{deviceStateConnected, deviceStateDown},
127 currentState: deviceStateUp,
128 before: []TransitionHandler{dh.doStateUp}}
129 // If olt DOWN indication comes then do sate down
130 transitionMap.transitions[DeviceDownInd] =
131 Transition{
Girish Gowdra852ad912021-05-04 00:05:50 -0700132 previousState: []DeviceState{deviceStateUp, deviceStateConnected},
Girish Gowdru0c588b22019-04-23 23:24:56 -0400133 currentState: deviceStateDown,
134 before: []TransitionHandler{dh.doStateDown}}
135
136 return &transitionMap
137}
138
139// funcName gets the handler function name
140func funcName(f interface{}) string {
141 p := reflect.ValueOf(f).Pointer()
142 rf := runtime.FuncForPC(p)
143 return rf.Name()
144}
145
146// isValidTransition checks for the new state transition is valid from current state
147func (tMap *TransitionMap) isValidTransition(trigger Trigger) bool {
148 // Validate the state transition
149 for _, state := range tMap.transitions[trigger].previousState {
150 if tMap.currentDeviceState == state {
151 return true
152 }
153 }
154 return false
155}
156
157// Handle moves the state machine to next state based on the trigger and invokes the before and
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700158// after handlers if the transition is a valid transition
npujarec5762e2020-01-01 14:08:48 +0530159func (tMap *TransitionMap) Handle(ctx context.Context, trigger Trigger) {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400160
161 // Check whether the transtion is valid from current state
162 if !tMap.isValidTransition(trigger) {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000163 logger.Errorw(ctx, "invalid-transition-triggered",
Shrey Baid26912972020-04-16 21:02:31 +0530164 log.Fields{
165 "current-state": tMap.currentDeviceState,
166 "trigger": trigger})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400167 return
168 }
169
170 // Invoke the before handlers
171 beforeHandlers := tMap.transitions[trigger].before
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700172 if beforeHandlers == nil {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000173 logger.Debugw(ctx, "no-handlers-for-before", log.Fields{"trigger": trigger})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400174 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700175 for _, handler := range beforeHandlers {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000176 logger.Debugw(ctx, "running-before-handler", log.Fields{"handler": funcName(handler)})
npujarec5762e2020-01-01 14:08:48 +0530177 if err := handler(ctx); err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700178 // TODO handle error
Neha Sharma96b7bf22020-06-15 10:37:32 +0000179 logger.Error(ctx, err)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700180 return
181 }
182 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400183
184 // Update the state
185 tMap.currentDeviceState = tMap.transitions[trigger].currentState
Neha Sharma96b7bf22020-06-15 10:37:32 +0000186 logger.Debugw(ctx, "updated-device-state ", log.Fields{"current-device-state": tMap.currentDeviceState})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400187
188 // Invoke the after handlers
189 afterHandlers := tMap.transitions[trigger].after
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700190 if afterHandlers == nil {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000191 logger.Debugw(ctx, "no-handlers-for-after", log.Fields{"trigger": trigger})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400192 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700193 for _, handler := range afterHandlers {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000194 logger.Debugw(ctx, "running-after-handler", log.Fields{"handler": funcName(handler)})
npujarec5762e2020-01-01 14:08:48 +0530195 if err := handler(ctx); err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700196 // TODO handle error
Neha Sharma96b7bf22020-06-15 10:37:32 +0000197 logger.Error(ctx, err)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700198 return
199 }
200 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400201}