blob: 07ae169bc60d71612b360a0c5d0744c01c5b6497 [file] [log] [blame]
Phaneendra Manda4c62c802019-03-06 21:37:49 +05301/*
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 adaptercore
17
18import (
19 "context"
20 "errors"
21 "io"
22 "strconv"
23 "strings"
24 "sync"
25
26 "github.com/gogo/protobuf/proto"
27 com "github.com/opencord/voltha-go/adapters/common"
28 "github.com/opencord/voltha-go/common/log"
29 "github.com/opencord/voltha-go/protos/common"
30 ic "github.com/opencord/voltha-go/protos/inter_container"
31 of "github.com/opencord/voltha-go/protos/openflow_13"
32 oop "github.com/opencord/voltha-go/protos/openolt"
33 "github.com/opencord/voltha-go/protos/voltha"
34 "google.golang.org/grpc"
35)
36
37//DeviceHandler will interact with the OLT device.
38type DeviceHandler struct {
39 deviceId string
40 deviceType string
41 device *voltha.Device
42 coreProxy *com.CoreProxy
43 openOLT *OpenOLT
44 nniPort *voltha.Port
45 ponPort *voltha.Port
46 exitChannel chan int
47 lockDevice sync.RWMutex
48 client oop.OpenoltClient
49 transitionMap *TransitionMap
50 clientCon *grpc.ClientConn
51}
52
53//NewDeviceHandler creates a new device handler
54func NewDeviceHandler(cp *com.CoreProxy, device *voltha.Device, adapter *OpenOLT) *DeviceHandler {
55 var dh DeviceHandler
56 dh.coreProxy = cp
57 cloned := (proto.Clone(device)).(*voltha.Device)
58 dh.deviceId = cloned.Id
59 dh.deviceType = cloned.Type
60 dh.device = cloned
61 dh.openOLT = adapter
62 dh.exitChannel = make(chan int, 1)
63 dh.lockDevice = sync.RWMutex{}
64
65 //TODO initialize the support classes.
66 return &dh
67}
68
69// start save the device to the data model
70func (dh *DeviceHandler) start(ctx context.Context) {
71 dh.lockDevice.Lock()
72 defer dh.lockDevice.Unlock()
73 log.Debugw("starting-device-agent", log.Fields{"device": dh.device})
74 // Add the initial device to the local model
75 log.Debug("device-agent-started")
76}
77
78// stop stops the device dh. Not much to do for now
79func (dh *DeviceHandler) stop(ctx context.Context) {
80 dh.lockDevice.Lock()
81 defer dh.lockDevice.Unlock()
82 log.Debug("stopping-device-agent")
83 dh.exitChannel <- 1
84 log.Debug("device-agent-stopped")
85}
86
87func macAddressToUint32Array(mac string) []uint32 {
88 slist := strings.Split(mac, ":")
89 result := make([]uint32, len(slist))
90 var err error
91 var tmp int64
92 for index, val := range slist {
93 if tmp, err = strconv.ParseInt(val, 16, 32); err != nil {
94 return []uint32{1, 2, 3, 4, 5, 6}
95 }
96 result[index] = uint32(tmp)
97 }
98 return result
99}
100
101func portName(portNum uint32, portType voltha.Port_PortType, intfId uint32) string {
102
103 if portType == voltha.Port_PON_OLT {
104 return "pon-" + string(portNum)
105 } else if portType == voltha.Port_ETHERNET_NNI {
106 return "nni-" + string(intfId)
107 } else if portType == voltha.Port_ETHERNET_UNI {
108 log.Errorw("local UNI management not supported", log.Fields{})
109 }
110 return ""
111}
112
113func (dh *DeviceHandler) addPort(intfId uint32, portType voltha.Port_PortType, state string) {
114 var operStatus common.OperStatus_OperStatus
115 if state == "up" {
116 operStatus = voltha.OperStatus_ACTIVE
117 } else {
118 operStatus = voltha.OperStatus_DISCOVERED
119 }
120
121 // TODO
122 //portNum := platform.intfIdToPortNo(intfId, portType)
123 portNum := intfId
124
125 label := portName(portNum, portType, intfId)
126 // Now create the PON Port
127 ponPort := &voltha.Port{
128 PortNo: portNum,
129 Label: label,
130 Type: portType,
131 OperStatus: operStatus,
132 }
133
134 // Synchronous call to update device - this method is run in its own go routine
135 if err := dh.coreProxy.PortCreated(nil, dh.device.Id, ponPort); err != nil {
136 log.Errorw("error-creating-nni-port", log.Fields{"deviceId": dh.device.Id, "error": err})
137 }
138}
139
140// readIndications to read the indications from the OLT device
141func (dh *DeviceHandler) readIndications() {
142 indications, err := dh.client.EnableIndication(context.Background(), new(oop.Empty))
143 if err != nil {
144 log.Errorw("Failed to read indications", log.Fields{"err": err})
145 return
146 }
147 if indications == nil {
148 log.Errorw("Indications is nil", log.Fields{})
149 return
150 }
151 for {
152 indication, err := indications.Recv()
153 if err == io.EOF {
154 break
155 }
156 if err != nil {
157 log.Infow("Failed to read from indications", log.Fields{"err": err})
158 continue
159 }
160 switch indication.Data.(type) {
161 case *oop.Indication_OltInd:
162 oltInd := indication.GetOltInd()
163 if oltInd.OperState == "up" {
164 dh.transitionMap.Handle(DeviceUpInd)
165 } else if oltInd.OperState == "down" {
166 dh.transitionMap.Handle(DeviceDownInd)
167 }
168 case *oop.Indication_IntfInd:
169
170 intfInd := indication.GetIntfInd()
171 go dh.addPort(intfInd.GetIntfId(), voltha.Port_PON_OLT, intfInd.GetOperState())
172 log.Infow("Received interface indication ", log.Fields{"InterfaceInd": intfInd})
173 case *oop.Indication_IntfOperInd:
174 intfOperInd := indication.GetIntfOperInd()
175 if intfOperInd.GetType() == "nni" {
176 go dh.addPort(intfOperInd.GetIntfId(), voltha.Port_ETHERNET_NNI, intfOperInd.GetOperState())
177 } else if intfOperInd.GetType() == "pon" {
178 // TODO: Check what needs to be handled here for When PON PORT down, ONU will be down
179 // Handle pon port update
180 }
181 log.Infow("Received interface oper indication ", log.Fields{"InterfaceOperInd": intfOperInd})
182 case *oop.Indication_OnuDiscInd:
183 onuDiscInd := indication.GetOnuDiscInd()
184 log.Infow("Received Onu discovery indication ", log.Fields{"OnuDiscInd": onuDiscInd})
185 // TODO Get onu ID from the resource manager
186 onuId := 0
187 go dh.coreProxy.ChildDeviceDetected(nil, dh.device.Id, int(onuDiscInd.GetIntfId()),
188 "brcm_openomci_onu", int(onuDiscInd.GetIntfId()), string(onuDiscInd.SerialNumber.GetVendorId()),
189 string(onuDiscInd.SerialNumber.GetVendorSpecific()), int64(onuId))
190 case *oop.Indication_OnuInd:
191 onuInd := indication.GetOnuInd()
192 log.Infow("Received Onu indication ", log.Fields{"OnuInd": onuInd})
193 case *oop.Indication_OmciInd:
194 omciInd := indication.GetOmciInd()
195 log.Infow("Received Omci indication ", log.Fields{"OmciInd": omciInd})
196 case *oop.Indication_PktInd:
197 pktInd := indication.GetPktInd()
198 log.Infow("Received pakcet indication ", log.Fields{"PktInd": pktInd})
199 case *oop.Indication_PortStats:
200 portStats := indication.GetPortStats()
201 log.Infow("Received port stats indication", log.Fields{"PortStats": portStats})
202 case *oop.Indication_FlowStats:
203 flowStats := indication.GetFlowStats()
204 log.Infow("Received flow stats", log.Fields{"FlowStats": flowStats})
205 case *oop.Indication_AlarmInd:
206 alarmInd := indication.GetAlarmInd()
207 log.Infow("Received alarm indication ", log.Fields{"AlarmInd": alarmInd})
208 }
209 }
210}
211
212// doStateUp handle the olt up indication and update to voltha core
213func (dh *DeviceHandler) doStateUp() error {
214 // Synchronous call to update device state - this method is run in its own go routine
215 if err := dh.coreProxy.DeviceStateUpdate(context.Background(), dh.device.Id, voltha.ConnectStatus_REACHABLE,
216 voltha.OperStatus_ACTIVE); err != nil {
217 log.Errorw("Failed to update device with OLT UP indication", log.Fields{"deviceId": dh.device.Id, "error": err})
218 return err
219 }
220 return nil
221}
222
223// doStateDown handle the olt down indication
224func (dh *DeviceHandler) doStateDown() error {
225 //TODO Handle oper state down
226 return nil
227}
228
229// doStateInit dial the grpc before going to init state
230func (dh *DeviceHandler) doStateInit() error {
231 var err error
232 dh.clientCon, err = grpc.Dial(dh.device.GetHostAndPort(), grpc.WithInsecure())
233 if err != nil {
234 log.Errorw("Failed to dial device", log.Fields{"DeviceId": dh.deviceId, "HostAndPort": dh.device.GetHostAndPort(), "err": err})
235 return err
236 }
237 return nil
238}
239
240// postInit create olt client instance to invoke RPC on the olt device
241func (dh *DeviceHandler) postInit() error {
242 dh.client = oop.NewOpenoltClient(dh.clientCon)
243 dh.transitionMap.Handle(GrpcConnected)
244 return nil
245}
246
247// doStateConnected get the device info and update to voltha core
248func (dh *DeviceHandler) doStateConnected() error {
249 deviceInfo, err := dh.client.GetDeviceInfo(context.Background(), new(oop.Empty))
250 if err != nil {
251 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
252 return err
253 }
254 if deviceInfo == nil {
255 log.Errorw("Device info is nil", log.Fields{})
256 return errors.New("Failed to get device info from OLT")
257 }
258
259 dh.device.Root = true
260 dh.device.Vendor = deviceInfo.Vendor
261 dh.device.Model = deviceInfo.Model
262 dh.device.ConnectStatus = voltha.ConnectStatus_REACHABLE
263 dh.device.SerialNumber = deviceInfo.DeviceSerialNumber
264 dh.device.HardwareVersion = deviceInfo.HardwareVersion
265 dh.device.FirmwareVersion = deviceInfo.FirmwareVersion
266 // TODO : Check whether this MAC address is learnt from SDPON or need to send from device
267 dh.device.MacAddress = "0a:0b:0c:0d:0e:0f"
268
269 // Synchronous call to update device - this method is run in its own go routine
270 if err := dh.coreProxy.DeviceUpdate(nil, dh.device); err != nil {
271 log.Errorw("error-updating-device", log.Fields{"deviceId": dh.device.Id, "error": err})
272 }
273
274 // Start reading indications
275 go dh.readIndications()
276 return nil
277}
278
279// AdoptDevice adopts the OLT device
280func (dh *DeviceHandler) AdoptDevice(device *voltha.Device) {
281 dh.transitionMap = NewTransitionMap(dh)
282 log.Infow("AdoptDevice", log.Fields{"deviceId": device.Id, "Address": device.GetHostAndPort()})
283 dh.transitionMap.Handle(DeviceInit)
284}
285
286// GetOfpDeviceInfo Get the Ofp device information
287func (dh *DeviceHandler) GetOfpDeviceInfo(device *voltha.Device) (*ic.SwitchCapability, error) {
288 return &ic.SwitchCapability{
289 Desc: &of.OfpDesc{
290 HwDesc: "open_pon",
291 SwDesc: "open_pon",
292 SerialNum: dh.device.SerialNumber,
293 },
294 SwitchFeatures: &of.OfpSwitchFeatures{
295 NBuffers: 256,
296 NTables: 2,
297 Capabilities: uint32(of.OfpCapabilities_OFPC_FLOW_STATS |
298 of.OfpCapabilities_OFPC_TABLE_STATS |
299 of.OfpCapabilities_OFPC_PORT_STATS |
300 of.OfpCapabilities_OFPC_GROUP_STATS),
301 },
302 }, nil
303}
304
305// GetOfpPortInfo Get Ofp port information
306func (dh *DeviceHandler) GetOfpPortInfo(device *voltha.Device, portNo int64) (*ic.PortCapability, error) {
307 cap := uint32(of.OfpPortFeatures_OFPPF_1GB_FD | of.OfpPortFeatures_OFPPF_FIBER)
308 return &ic.PortCapability{
309 Port: &voltha.LogicalPort{
310 OfpPort: &of.OfpPort{
311 HwAddr: macAddressToUint32Array(dh.device.MacAddress),
312 Config: 0,
313 State: uint32(of.OfpPortState_OFPPS_LIVE),
314 Curr: cap,
315 Advertised: cap,
316 Peer: cap,
317 CurrSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
318 MaxSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
319 },
320 DeviceId: dh.device.Id,
321 DevicePortNo: uint32(portNo),
322 },
323 }, nil
324}
325
326// Process_inter_adapter_message process inter adater message
327func (dh *DeviceHandler) Process_inter_adapter_message(msg *ic.InterAdapterMessage) error {
328 // TODO
329 log.Debugw("Process_inter_adapter_message", log.Fields{"msgId": msg.Header.Id})
330 return nil
331}
332