blob: aa137485cff356c6da0c832fae11729db82b57f2 [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 */
16package core
17
18import (
19 "context"
20 "github.com/gogo/protobuf/proto"
21 "github.com/opencord/voltha-go/common/log"
22 "github.com/opencord/voltha-go/db/model"
23 "github.com/opencord/voltha-go/protos/core_adapter"
24 "github.com/opencord/voltha-go/protos/voltha"
25 "google.golang.org/grpc/codes"
26 "google.golang.org/grpc/status"
27 "reflect"
28)
29
30type DeviceAgent struct {
31 deviceId string
32 lastData *voltha.Device
33 adapterProxy *AdapterProxy
34 deviceMgr *DeviceManager
35 localDataProxy *model.Proxy
36 exitChannel chan int
37}
38
39func newDeviceAgent(ap *AdapterProxy, device *voltha.Device, deviceMgr *DeviceManager, ldProxy *model.Proxy) *DeviceAgent {
40 var agent DeviceAgent
41 device.Id = CreateDeviceId()
42 agent.deviceId = device.Id
43 agent.adapterProxy = ap
44 agent.lastData = device
45 agent.deviceMgr = deviceMgr
46 agent.exitChannel = make(chan int, 1)
47 agent.localDataProxy = ldProxy
48 return &agent
49}
50
51func (agent *DeviceAgent) start(ctx context.Context) {
52 log.Debugw("starting-device-agent", log.Fields{"device": agent.lastData})
53 // Add the initial device to the local model
54 if added := agent.localDataProxy.Add("/devices", agent.lastData, ""); added == nil {
55 log.Errorw("failed-to-add-device", log.Fields{"deviceId": agent.deviceId})
56 }
57 log.Debug("device-agent-started")
58}
59
60func (agent *DeviceAgent) Stop(ctx context.Context) {
61 log.Debug("stopping-device-agent")
62 agent.exitChannel <- 1
63 log.Debug("device-agent-stopped")
64}
65
66func (agent *DeviceAgent) enableDevice(ctx context.Context) error {
67 log.Debugw("enableDevice", log.Fields{"id": agent.lastData.Id, "device": agent.lastData})
68 // Update the device status
69 if device, err := agent.deviceMgr.getDevice(agent.deviceId); err != nil {
70 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
71 } else {
72 cloned := reflect.ValueOf(device).Elem().Interface().(voltha.Device)
73 cloned.AdminState = voltha.AdminState_ENABLED
74 cloned.OperStatus = voltha.OperStatus_ACTIVATING
75 if afterUpdate := agent.localDataProxy.Update("/devices/"+agent.deviceId, &cloned, false, ""); afterUpdate == nil {
76 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
77 } else {
78 if err := agent.adapterProxy.AdoptDevice(ctx, &cloned); err != nil {
79 log.Debugw("enableDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
80 return err
81 }
82 agent.lastData = &cloned
83 }
84 }
85 return nil
86}
87
88func (agent *DeviceAgent) getNNIPorts(ctx context.Context) *voltha.Ports {
89 log.Debugw("getNNIPorts", log.Fields{"id": agent.deviceId})
90 ports := &voltha.Ports{}
91 if device, _ := agent.deviceMgr.getDevice(agent.deviceId); device != nil {
92 for _, port := range device.Ports {
93 if port.Type == voltha.Port_ETHERNET_NNI {
94 ports.Items = append(ports.Items, port)
95 }
96 }
97 }
98 return ports
99}
100
101func (agent *DeviceAgent) getSwitchCapability(ctx context.Context) (*core_adapter.SwitchCapability, error) {
102 log.Debugw("getSwitchCapability", log.Fields{"deviceId": agent.deviceId})
103 if device, err := agent.deviceMgr.getDevice(agent.deviceId); device == nil {
104 return nil, err
105 } else {
106 var switchCap *core_adapter.SwitchCapability
107 var err error
108 if switchCap, err = agent.adapterProxy.GetOfpDeviceInfo(ctx, device); err != nil {
109 log.Debugw("getSwitchCapability-error", log.Fields{"id": device.Id, "error": err})
110 return nil, err
111 }
112 return switchCap, nil
113 }
114}
115
116func (agent *DeviceAgent) getPortCapability(ctx context.Context, portNo uint32) (*core_adapter.PortCapability, error) {
117 log.Debugw("getPortCapability", log.Fields{"deviceId": agent.deviceId})
118 if device, err := agent.deviceMgr.getDevice(agent.deviceId); device == nil {
119 return nil, err
120 } else {
121 var portCap *core_adapter.PortCapability
122 var err error
123 if portCap, err = agent.adapterProxy.GetOfpPortInfo(ctx, device, portNo); err != nil {
124 log.Debugw("getPortCapability-error", log.Fields{"id": device.Id, "error": err})
125 return nil, err
126 }
127 return portCap, nil
128 }
129}
130
131func (agent *DeviceAgent) updateDevice(device *voltha.Device) error {
132 log.Debugw("updateDevice", log.Fields{"deviceId": device.Id})
133 // Get the dev info from the model
134 if storedData, err := agent.deviceMgr.getDevice(device.Id); err != nil {
135 return status.Errorf(codes.NotFound, "%s", device.Id)
136 } else {
137 // store the changed data
138 cloned := (proto.Clone(device)).(*voltha.Device)
139 afterUpdate := agent.localDataProxy.Update("/devices/"+device.Id, cloned, false, "")
140 if afterUpdate == nil {
141 return status.Errorf(codes.Internal, "%s", device.Id)
142 }
143 // Perform the state transition
144 if err := agent.deviceMgr.processTransition(storedData, cloned); err != nil {
145 log.Warnw("process-transition-error", log.Fields{"deviceid": device.Id, "error": err})
146 return err
147 }
148 return nil
149 }
150}
151
152func (agent *DeviceAgent) updateDeviceState(operState *core_adapter.IntType, connState *core_adapter.IntType) error {
153 // Work only on latest data
154 if storeDevice, err := agent.deviceMgr.getDevice(agent.deviceId); err != nil {
155 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
156 } else {
157 // clone the device
158 cloned := reflect.ValueOf(storeDevice).Elem().Interface().(voltha.Device)
159 if operState != nil {
160 cloned.OperStatus = voltha.OperStatus_OperStatus(operState.Val)
161 }
162 if connState != nil {
163 cloned.ConnectStatus = voltha.ConnectStatus_ConnectStatus(connState.Val)
164 }
165 log.Debugw("DeviceStateUpdate-device", log.Fields{"device": cloned})
166 // Store the device
167 if afterUpdate := agent.localDataProxy.Update("/devices/"+agent.deviceId, &cloned, false, ""); afterUpdate == nil {
168 return status.Errorf(codes.Internal, "%s", agent.deviceId)
169 }
170 // Perform the state transition
171 if err := agent.deviceMgr.processTransition(storeDevice, &cloned); err != nil {
172 log.Warnw("process-transition-error", log.Fields{"deviceid": agent.deviceId, "error": err})
173 return err
174 }
175 return nil
176 }
177}
178
179func (agent *DeviceAgent) updatePmConfigs(pmConfigs *voltha.PmConfigs) error {
180 log.Debug("updatePmConfigs")
181 // Work only on latest data
182 if storeDevice, err := agent.deviceMgr.getDevice(agent.deviceId); err != nil {
183 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
184 } else {
185 // clone the device
186 cloned := reflect.ValueOf(storeDevice).Elem().Interface().(voltha.Device)
187 cp := proto.Clone(pmConfigs)
188 cloned.PmConfigs = cp.(*voltha.PmConfigs)
189 // Store the device
190 afterUpdate := agent.localDataProxy.Update("/devices/"+agent.deviceId, &cloned, false, "")
191 if afterUpdate == nil {
192 return status.Errorf(codes.Internal, "%s", agent.deviceId)
193 }
194 return nil
195 }
196}
197
198func (agent *DeviceAgent) addPort(port *voltha.Port) error {
199 log.Debug("addPort")
200 // Work only on latest data
201 if storeDevice, err := agent.deviceMgr.getDevice(agent.deviceId); err != nil {
202 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
203 } else {
204 // clone the device
205 cloned := reflect.ValueOf(storeDevice).Elem().Interface().(voltha.Device)
206 if cloned.Ports == nil {
207 // First port
208 cloned.Ports = make([]*voltha.Port, 0)
209 }
210 cp := proto.Clone(port)
211 cloned.Ports = append(cloned.Ports, cp.(*voltha.Port))
212 // Store the device
213 afterUpdate := agent.localDataProxy.Update("/devices/"+agent.deviceId, &cloned, false, "")
214 if afterUpdate == nil {
215 return status.Errorf(codes.Internal, "%s", agent.deviceId)
216 }
217 return nil
218 }
219}
220
221// TODO: A generic device update by attribute
222func (agent *DeviceAgent) updateDeviceAttribute(name string, value interface{}) {
223 if value == nil {
224 return
225 }
226 var storeDevice *voltha.Device
227 var err error
228 if storeDevice, err = agent.deviceMgr.getDevice(agent.deviceId); err != nil {
229 return
230 }
231 updated := false
232 s := reflect.ValueOf(storeDevice).Elem()
233 if s.Kind() == reflect.Struct {
234 // exported field
235 f := s.FieldByName(name)
236 if f.IsValid() && f.CanSet() {
237 switch f.Kind() {
238 case reflect.String:
239 f.SetString(value.(string))
240 updated = true
241 case reflect.Uint32:
242 f.SetUint(uint64(value.(uint32)))
243 updated = true
244 case reflect.Bool:
245 f.SetBool(value.(bool))
246 updated = true
247 }
248 }
249 }
250 log.Debugw("update-field-status", log.Fields{"device": storeDevice, "name": name, "updated": updated})
251 // Save the data
252 cloned := reflect.ValueOf(storeDevice).Elem().Interface().(voltha.Device)
253 if afterUpdate := agent.localDataProxy.Update("/devices/"+agent.deviceId, &cloned, false, ""); afterUpdate == nil {
254 log.Warnw("attribute-update-failed", log.Fields{"attribute": name, "value": value})
255 }
256 return
257}