blob: e11f9183b334dc8478b91db4f49c88477564ca27 [file] [log] [blame]
Holger Hildebrandtfa074992020-03-27 15:42:06 +00001/*
2 * Copyright 2020-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 */
16
17//Package adaptercoreont provides the utility for onu devices, flows and statistics
18package adaptercoreont
19
20import (
21 "context"
22 "reflect"
23 "runtime"
24
25 "github.com/opencord/voltha-lib-go/v3/pkg/log"
26)
27
28// DeviceState ONU Device state
29type DeviceState int
30
31//ONU device state machine may have to be adapted to specific ONU Adapter device needd ... !!!!!
32
33const (
34 // deviceStateNull OLT is not instantiated
35 deviceStateNull DeviceState = iota
36 // deviceStateInit OLT is instantiated
37 deviceStateInit
38 // deviceStateConnected Grpc session established with OLT
39 deviceStateConnected
40 // deviceStateUp Admin state of OLT is UP
41 deviceStateUp
42 // deviceStateDown Admin state of OLT is down
43 deviceStateDown
44)
45
46// Trigger for changing the state
47type Trigger int
48
49const (
50 // DeviceInit Go to Device init state
51 DeviceInit Trigger = iota
52 // GrpcConnected Go to connected state
53 GrpcConnected
54 // DeviceUpInd Go to Device up state
55 DeviceUpInd
56 // DeviceDownInd Go to Device down state
57 DeviceDownInd
58 // GrpcDisconnected Go to Device init state
59 GrpcDisconnected
60)
61
62// TransitionHandler function type for handling transition
63type TransitionHandler func(ctx context.Context) error
64
65// Transition to store state machine
66type Transition struct {
67 previousState []DeviceState
68 currentState DeviceState
69 before []TransitionHandler
70 after []TransitionHandler
71}
72
73// TransitionMap to store all the states and current device state
74type TransitionMap struct {
75 transitions map[Trigger]Transition
76 currentDeviceState DeviceState
77}
78
79// OpenOnuDevice state machine:
80//
81// null ----> init ------> connected -----> up -----> down
82// ^ ^ | ^ | |
83// | | | | | |
84// | +-------------+ +---------+ |
85// | |
86// +-----------------------------------------+
87
88// NewTransitionMap create a new state machine with all the transitions
89func NewTransitionMap(dh *DeviceHandler) *TransitionMap {
90 var transitionMap TransitionMap
91 transitionMap.currentDeviceState = deviceStateNull
92 transitionMap.transitions = make(map[Trigger]Transition)
93 // In doInit create the Pon port, then set the device communication
94 transitionMap.transitions[DeviceInit] =
95 Transition{
96 previousState: []DeviceState{deviceStateNull, deviceStateDown},
97 currentState: deviceStateInit,
98 before: []TransitionHandler{dh.doStateInit},
99 after: []TransitionHandler{dh.postInit}}
100 // not yet relevant?
101 transitionMap.transitions[GrpcDisconnected] =
102 Transition{
103 previousState: []DeviceState{deviceStateConnected, deviceStateDown},
104 currentState: deviceStateInit,
105 before: []TransitionHandler{dh.doStateInit},
106 after: []TransitionHandler{dh.postInit}}
107 // in doConnected, create logical device and read the indications
108 transitionMap.transitions[GrpcConnected] =
109 Transition{
110 previousState: []DeviceState{deviceStateInit},
111 currentState: deviceStateConnected,
112 before: []TransitionHandler{dh.doStateConnected}}
113
114 // Once the olt UP is indication received, then do state up
115 transitionMap.transitions[DeviceUpInd] =
116 Transition{
117 previousState: []DeviceState{deviceStateConnected, deviceStateDown},
118 currentState: deviceStateUp,
119 before: []TransitionHandler{dh.doStateUp}}
120 // If olt DOWN indication comes then do sate down
121 transitionMap.transitions[DeviceDownInd] =
122 Transition{
123 previousState: []DeviceState{deviceStateUp},
124 currentState: deviceStateDown,
125 before: []TransitionHandler{dh.doStateDown}}
126
127 return &transitionMap
128}
129
130// funcName gets the handler function name
131func funcName(f interface{}) string {
132 p := reflect.ValueOf(f).Pointer()
133 rf := runtime.FuncForPC(p)
134 return rf.Name()
135}
136
137// isValidTransition checks for the new state transition is valid from current state
138func (tMap *TransitionMap) isValidTransition(trigger Trigger) bool {
139 // Validate the state transition
140 for _, state := range tMap.transitions[trigger].previousState {
141 if tMap.currentDeviceState == state {
142 return true
143 }
144 }
145 return false
146}
147
148// Handle moves the state machine to next state based on the trigger and invokes the before and
149// after handlers if the transition is a valid transition
150func (tMap *TransitionMap) Handle(ctx context.Context, trigger Trigger) {
151
152 // Check whether the transtion is valid from current state
153 if !tMap.isValidTransition(trigger) {
154 log.Errorw("Invalid transition triggered ", log.Fields{"CurrentState": tMap.currentDeviceState, "Trigger": trigger})
155 return
156 }
157
158 // Invoke the before handlers
159 beforeHandlers := tMap.transitions[trigger].before
160 if beforeHandlers == nil {
161 log.Debugw("No handlers for before", log.Fields{"trigger": trigger})
162 }
163 for _, handler := range beforeHandlers {
164 log.Debugw("running-before-handler", log.Fields{"handler": funcName(handler)})
165 if err := handler(ctx); err != nil {
166 // TODO handle error
167 log.Error(err)
168 return
169 }
170 }
171
172 // Update the state
173 tMap.currentDeviceState = tMap.transitions[trigger].currentState
174 log.Debugw("Updated device state ", log.Fields{"CurrentDeviceState": tMap.currentDeviceState})
175
176 // Invoke the after handlers
177 afterHandlers := tMap.transitions[trigger].after
178 if afterHandlers == nil {
179 log.Debugw("No handlers for after", log.Fields{"trigger": trigger})
180 }
181 for _, handler := range afterHandlers {
182 log.Debugw("running-after-handler", log.Fields{"handler": funcName(handler)})
183 if err := handler(ctx); err != nil {
184 // TODO handle error
185 log.Error(err)
186 return
187 }
188 }
189}