blob: 866f8154936b6b4ced16b10e1590884945bf5622 [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 (
cuilin20187b2a8c32019-03-26 19:52:28 -070019 "context"
20 "errors"
21 "fmt"
22 "io"
23 "strconv"
24 "strings"
25 "sync"
26 "time"
Phaneendra Manda4c62c802019-03-06 21:37:49 +053027
cuilin20187b2a8c32019-03-26 19:52:28 -070028 "github.com/gogo/protobuf/proto"
29 "github.com/golang/protobuf/ptypes"
manikkaraj k9eb6cac2019-05-09 12:32:03 -040030 "github.com/mdlayher/ethernet"
cuilin20187b2a8c32019-03-26 19:52:28 -070031 com "github.com/opencord/voltha-go/adapters/common"
32 "github.com/opencord/voltha-go/common/log"
Girish Gowdru0c588b22019-04-23 23:24:56 -040033 rsrcMgr "github.com/opencord/voltha-openolt-adapter/adaptercore/resourcemanager"
manikkaraj kbf256be2019-03-25 00:13:48 +053034 "github.com/opencord/voltha-protos/go/common"
35 ic "github.com/opencord/voltha-protos/go/inter_container"
36 of "github.com/opencord/voltha-protos/go/openflow_13"
37 oop "github.com/opencord/voltha-protos/go/openolt"
manikkaraj kbf256be2019-03-25 00:13:48 +053038 "github.com/opencord/voltha-protos/go/voltha"
cuilin20187b2a8c32019-03-26 19:52:28 -070039 "google.golang.org/grpc"
Phaneendra Manda4c62c802019-03-06 21:37:49 +053040)
41
42//DeviceHandler will interact with the OLT device.
43type DeviceHandler struct {
cuilin20187b2a8c32019-03-26 19:52:28 -070044 deviceId string
45 deviceType string
Girish Gowdru5ba46c92019-04-25 05:00:05 -040046 adminState string
cuilin20187b2a8c32019-03-26 19:52:28 -070047 device *voltha.Device
48 coreProxy *com.CoreProxy
manikkaraj kbf256be2019-03-25 00:13:48 +053049 AdapterProxy *com.AdapterProxy
cuilin20187b2a8c32019-03-26 19:52:28 -070050 openOLT *OpenOLT
51 nniPort *voltha.Port
52 ponPort *voltha.Port
53 exitChannel chan int
54 lockDevice sync.RWMutex
manikkaraj kbf256be2019-03-25 00:13:48 +053055 Client oop.OpenoltClient
cuilin20187b2a8c32019-03-26 19:52:28 -070056 transitionMap *TransitionMap
57 clientCon *grpc.ClientConn
manikkaraj kbf256be2019-03-25 00:13:48 +053058 flowMgr *OpenOltFlowMgr
59 resourceMgr *rsrcMgr.OpenOltResourceMgr
Phaneendra Manda4c62c802019-03-06 21:37:49 +053060}
61
62//NewDeviceHandler creates a new device handler
cuilin20187b2a8c32019-03-26 19:52:28 -070063func NewDeviceHandler(cp *com.CoreProxy, ap *com.AdapterProxy, device *voltha.Device, adapter *OpenOLT) *DeviceHandler {
64 var dh DeviceHandler
65 dh.coreProxy = cp
Girish Gowdru0c588b22019-04-23 23:24:56 -040066 dh.AdapterProxy = ap
cuilin20187b2a8c32019-03-26 19:52:28 -070067 cloned := (proto.Clone(device)).(*voltha.Device)
68 dh.deviceId = cloned.Id
69 dh.deviceType = cloned.Type
Girish Gowdru5ba46c92019-04-25 05:00:05 -040070 dh.adminState = "up"
cuilin20187b2a8c32019-03-26 19:52:28 -070071 dh.device = cloned
72 dh.openOLT = adapter
73 dh.exitChannel = make(chan int, 1)
74 dh.lockDevice = sync.RWMutex{}
Phaneendra Manda4c62c802019-03-06 21:37:49 +053075
cuilin20187b2a8c32019-03-26 19:52:28 -070076 //TODO initialize the support classes.
77 return &dh
Phaneendra Manda4c62c802019-03-06 21:37:49 +053078}
79
80// start save the device to the data model
81func (dh *DeviceHandler) start(ctx context.Context) {
cuilin20187b2a8c32019-03-26 19:52:28 -070082 dh.lockDevice.Lock()
83 defer dh.lockDevice.Unlock()
84 log.Debugw("starting-device-agent", log.Fields{"device": dh.device})
85 // Add the initial device to the local model
86 log.Debug("device-agent-started")
Phaneendra Manda4c62c802019-03-06 21:37:49 +053087}
88
89// stop stops the device dh. Not much to do for now
90func (dh *DeviceHandler) stop(ctx context.Context) {
cuilin20187b2a8c32019-03-26 19:52:28 -070091 dh.lockDevice.Lock()
92 defer dh.lockDevice.Unlock()
93 log.Debug("stopping-device-agent")
94 dh.exitChannel <- 1
95 log.Debug("device-agent-stopped")
Phaneendra Manda4c62c802019-03-06 21:37:49 +053096}
97
98func macAddressToUint32Array(mac string) []uint32 {
cuilin20187b2a8c32019-03-26 19:52:28 -070099 slist := strings.Split(mac, ":")
100 result := make([]uint32, len(slist))
101 var err error
102 var tmp int64
103 for index, val := range slist {
104 if tmp, err = strconv.ParseInt(val, 16, 32); err != nil {
105 return []uint32{1, 2, 3, 4, 5, 6}
106 }
107 result[index] = uint32(tmp)
108 }
109 return result
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530110}
111
manikkaraj kbf256be2019-03-25 00:13:48 +0530112func GetportLabel(portNum uint32, portType voltha.Port_PortType) string {
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530113
Girish Gowdru0c588b22019-04-23 23:24:56 -0400114 if portType == voltha.Port_ETHERNET_NNI {
115 return fmt.Sprintf("nni-%d", portNum)
116 } else if portType == voltha.Port_PON_OLT {
117 return fmt.Sprintf("pon-%d", portNum)
cuilin20187b2a8c32019-03-26 19:52:28 -0700118 } else if portType == voltha.Port_ETHERNET_UNI {
119 log.Errorw("local UNI management not supported", log.Fields{})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400120 return ""
cuilin20187b2a8c32019-03-26 19:52:28 -0700121 }
122 return ""
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530123}
124
125func (dh *DeviceHandler) addPort(intfId uint32, portType voltha.Port_PortType, state string) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700126 var operStatus common.OperStatus_OperStatus
127 if state == "up" {
128 operStatus = voltha.OperStatus_ACTIVE
129 } else {
130 operStatus = voltha.OperStatus_DISCOVERED
131 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400132 portNum := IntfIdToPortNo(intfId, portType)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400133 label := GetportLabel(portNum, portType)
134 if len(label) == 0 {
135 log.Errorw("Invalid-port-label", log.Fields{"portNum": portNum, "portType": portType})
136 return
137 }
138 // Now create Port
139 port := &voltha.Port{
cuilin20187b2a8c32019-03-26 19:52:28 -0700140 PortNo: portNum,
141 Label: label,
142 Type: portType,
143 OperStatus: operStatus,
144 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400145 log.Debugw("Sending port update to core", log.Fields{"port": port})
cuilin20187b2a8c32019-03-26 19:52:28 -0700146 // Synchronous call to update device - this method is run in its own go routine
Girish Gowdru0c588b22019-04-23 23:24:56 -0400147 if err := dh.coreProxy.PortCreated(nil, dh.device.Id, port); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700148 log.Errorw("error-creating-nni-port", log.Fields{"deviceId": dh.device.Id, "error": err})
149 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530150}
151
152// readIndications to read the indications from the OLT device
153func (dh *DeviceHandler) readIndications() {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400154 indications, err := dh.Client.EnableIndication(context.Background(), new(oop.Empty))
cuilin20187b2a8c32019-03-26 19:52:28 -0700155 if err != nil {
156 log.Errorw("Failed to read indications", log.Fields{"err": err})
157 return
158 }
159 if indications == nil {
160 log.Errorw("Indications is nil", log.Fields{})
161 return
162 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400163 /* get device state */
164 device, err := dh.coreProxy.GetDevice(nil, dh.device.Id, dh.device.Id)
165 if err != nil || device == nil {
166 /*TODO: needs to handle error scenarios */
167 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
168
169 }
170 // When the device is in DISABLED and Adapter container restarts, we need to
171 // rebuild the locally maintained admin state.
172 if device.AdminState == voltha.AdminState_DISABLED {
173 dh.lockDevice.Lock()
174 dh.adminState = "down"
175 dh.lockDevice.Unlock()
176 }
177
cuilin20187b2a8c32019-03-26 19:52:28 -0700178 for {
179 indication, err := indications.Recv()
180 if err == io.EOF {
181 break
182 }
183 if err != nil {
184 log.Infow("Failed to read from indications", log.Fields{"err": err})
185 continue
186 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400187 // When OLT is admin down, allow only NNI operation status change indications.
188 if dh.adminState == "down" {
189 _, isIntfOperInd := indication.Data.(*oop.Indication_IntfOperInd)
190 if isIntfOperInd {
191 intfOperInd := indication.GetIntfOperInd()
192 if intfOperInd.GetType() == "nni" {
193 log.Infow("olt is admin down, allow nni ind", log.Fields{})
194 }
195 } else {
196 log.Infow("olt is admin down, ignore indication", log.Fields{})
197 continue
198 }
199 }
cuilin20187b2a8c32019-03-26 19:52:28 -0700200 switch indication.Data.(type) {
201 case *oop.Indication_OltInd:
202 oltInd := indication.GetOltInd()
203 if oltInd.OperState == "up" {
204 dh.transitionMap.Handle(DeviceUpInd)
205 } else if oltInd.OperState == "down" {
206 dh.transitionMap.Handle(DeviceDownInd)
207 }
208 case *oop.Indication_IntfInd:
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530209
cuilin20187b2a8c32019-03-26 19:52:28 -0700210 intfInd := indication.GetIntfInd()
211 go dh.addPort(intfInd.GetIntfId(), voltha.Port_PON_OLT, intfInd.GetOperState())
212 log.Infow("Received interface indication ", log.Fields{"InterfaceInd": intfInd})
213 case *oop.Indication_IntfOperInd:
214 intfOperInd := indication.GetIntfOperInd()
215 if intfOperInd.GetType() == "nni" {
216 go dh.addPort(intfOperInd.GetIntfId(), voltha.Port_ETHERNET_NNI, intfOperInd.GetOperState())
217 } else if intfOperInd.GetType() == "pon" {
218 // TODO: Check what needs to be handled here for When PON PORT down, ONU will be down
219 // Handle pon port update
220 }
221 log.Infow("Received interface oper indication ", log.Fields{"InterfaceOperInd": intfOperInd})
222 case *oop.Indication_OnuDiscInd:
223 onuDiscInd := indication.GetOnuDiscInd()
224 log.Infow("Received Onu discovery indication ", log.Fields{"OnuDiscInd": onuDiscInd})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400225 //onuId,err := dh.resourceMgr.GetONUID(onuDiscInd.GetIntfId())
226 //onuId,err := dh.resourceMgr.GetONUID(onuDiscInd.GetIntfId())
227 // TODO Get onu ID from the resource manager
cuilin20187b2a8c32019-03-26 19:52:28 -0700228 var onuId uint32 = 1
Girish Gowdru0c588b22019-04-23 23:24:56 -0400229 /*if err != nil{
230 log.Errorw("onu-id-unavailable",log.Fields{"intfId":onuDiscInd.GetIntfId()})
231 return
232 }*/
manikkaraj kbf256be2019-03-25 00:13:48 +0530233
cuilin20187b2a8c32019-03-26 19:52:28 -0700234 sn := dh.stringifySerialNumber(onuDiscInd.SerialNumber)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400235 //FIXME: Duplicate child devices being create in go routine
236 dh.onuDiscIndication(onuDiscInd, onuId, sn)
cuilin20187b2a8c32019-03-26 19:52:28 -0700237 case *oop.Indication_OnuInd:
238 onuInd := indication.GetOnuInd()
239 log.Infow("Received Onu indication ", log.Fields{"OnuInd": onuInd})
240 go dh.onuIndication(onuInd)
241 case *oop.Indication_OmciInd:
242 omciInd := indication.GetOmciInd()
243 log.Infow("Received Omci indication ", log.Fields{"OmciInd": omciInd})
244 if err := dh.omciIndication(omciInd); err != nil {
245 log.Errorw("send-omci-indication-errr", log.Fields{"error": err, "omciInd": omciInd})
246 }
247 case *oop.Indication_PktInd:
248 pktInd := indication.GetPktInd()
249 log.Infow("Received pakcet indication ", log.Fields{"PktInd": pktInd})
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400250 go dh.handlePacketIndication(pktInd)
cuilin20187b2a8c32019-03-26 19:52:28 -0700251 case *oop.Indication_PortStats:
252 portStats := indication.GetPortStats()
253 log.Infow("Received port stats indication", log.Fields{"PortStats": portStats})
254 case *oop.Indication_FlowStats:
255 flowStats := indication.GetFlowStats()
256 log.Infow("Received flow stats", log.Fields{"FlowStats": flowStats})
257 case *oop.Indication_AlarmInd:
258 alarmInd := indication.GetAlarmInd()
259 log.Infow("Received alarm indication ", log.Fields{"AlarmInd": alarmInd})
260 }
261 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530262}
263
264// doStateUp handle the olt up indication and update to voltha core
265func (dh *DeviceHandler) doStateUp() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400266 // Synchronous call to update device state - this method is run in its own go routine
cuilin20187b2a8c32019-03-26 19:52:28 -0700267 if err := dh.coreProxy.DeviceStateUpdate(context.Background(), dh.device.Id, voltha.ConnectStatus_REACHABLE,
Girish Gowdru0c588b22019-04-23 23:24:56 -0400268 voltha.OperStatus_ACTIVE); err != nil {
269 log.Errorw("Failed to update device with OLT UP indication", log.Fields{"deviceId": dh.device.Id, "error": err})
270 return err
271 }
272 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530273}
274
275// doStateDown handle the olt down indication
276func (dh *DeviceHandler) doStateDown() error {
cuilin20187b2a8c32019-03-26 19:52:28 -0700277 //TODO Handle oper state down
278 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530279}
280
281// doStateInit dial the grpc before going to init state
282func (dh *DeviceHandler) doStateInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400283 var err error
284 dh.clientCon, err = grpc.Dial(dh.device.GetHostAndPort(), grpc.WithInsecure())
285 if err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700286 log.Errorw("Failed to dial device", log.Fields{"DeviceId": dh.deviceId, "HostAndPort": dh.device.GetHostAndPort(), "err": err})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400287 return err
288 }
289 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530290}
291
292// postInit create olt client instance to invoke RPC on the olt device
293func (dh *DeviceHandler) postInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400294 dh.Client = oop.NewOpenoltClient(dh.clientCon)
295 dh.transitionMap.Handle(GrpcConnected)
296 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530297}
298
299// doStateConnected get the device info and update to voltha core
300func (dh *DeviceHandler) doStateConnected() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400301 log.Debug("OLT device has been connected")
302 deviceInfo, err := dh.Client.GetDeviceInfo(context.Background(), new(oop.Empty))
cuilin20187b2a8c32019-03-26 19:52:28 -0700303 if err != nil {
304 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
305 return err
306 }
307 if deviceInfo == nil {
308 log.Errorw("Device info is nil", log.Fields{})
309 return errors.New("Failed to get device info from OLT")
310 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400311 log.Debugw("Fetched device info", log.Fields{"deviceInfo": deviceInfo})
cuilin20187b2a8c32019-03-26 19:52:28 -0700312 dh.device.Root = true
313 dh.device.Vendor = deviceInfo.Vendor
314 dh.device.Model = deviceInfo.Model
315 dh.device.ConnectStatus = voltha.ConnectStatus_REACHABLE
316 dh.device.SerialNumber = deviceInfo.DeviceSerialNumber
317 dh.device.HardwareVersion = deviceInfo.HardwareVersion
318 dh.device.FirmwareVersion = deviceInfo.FirmwareVersion
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400319 // FIXME: Remove Hardcodings
cuilin20187b2a8c32019-03-26 19:52:28 -0700320 dh.device.MacAddress = "0a:0b:0c:0d:0e:0f"
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530321
cuilin20187b2a8c32019-03-26 19:52:28 -0700322 // Synchronous call to update device - this method is run in its own go routine
323 if err := dh.coreProxy.DeviceUpdate(nil, dh.device); err != nil {
324 log.Errorw("error-updating-device", log.Fields{"deviceId": dh.device.Id, "error": err})
325 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400326 KVStoreHostPort := fmt.Sprintf("%s:%d", dh.openOLT.KVStoreHost, dh.openOLT.KVStorePort)
327 // Instantiate resource manager
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400328 if dh.resourceMgr = rsrcMgr.NewResourceMgr(dh.deviceId, KVStoreHostPort, dh.openOLT.KVStoreType, dh.deviceType, deviceInfo); dh.resourceMgr == nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400329 log.Error("Error while instantiating resource manager")
330 return errors.New("Instantiating resource manager failed")
331 }
332 // Instantiate flow manager
333 if dh.flowMgr = NewFlowManager(dh, dh.resourceMgr); dh.flowMgr == nil {
334 log.Error("Error while instantiating flow manager")
335 return errors.New("Instantiating flow manager failed")
336 }
337 /* TODO: Instantiate Alarm , stats , BW managers */
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530338
cuilin20187b2a8c32019-03-26 19:52:28 -0700339 // Start reading indications
340 go dh.readIndications()
341 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530342}
343
344// AdoptDevice adopts the OLT device
345func (dh *DeviceHandler) AdoptDevice(device *voltha.Device) {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400346 dh.transitionMap = NewTransitionMap(dh)
cuilin20187b2a8c32019-03-26 19:52:28 -0700347 log.Infow("AdoptDevice", log.Fields{"deviceId": device.Id, "Address": device.GetHostAndPort()})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400348 dh.transitionMap.Handle(DeviceInit)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530349}
350
351// GetOfpDeviceInfo Get the Ofp device information
352func (dh *DeviceHandler) GetOfpDeviceInfo(device *voltha.Device) (*ic.SwitchCapability, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700353 return &ic.SwitchCapability{
354 Desc: &of.OfpDesc{
355 HwDesc: "open_pon",
356 SwDesc: "open_pon",
357 SerialNum: dh.device.SerialNumber,
358 },
359 SwitchFeatures: &of.OfpSwitchFeatures{
360 NBuffers: 256,
361 NTables: 2,
362 Capabilities: uint32(of.OfpCapabilities_OFPC_FLOW_STATS |
363 of.OfpCapabilities_OFPC_TABLE_STATS |
364 of.OfpCapabilities_OFPC_PORT_STATS |
365 of.OfpCapabilities_OFPC_GROUP_STATS),
366 },
367 }, nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530368}
369
370// GetOfpPortInfo Get Ofp port information
371func (dh *DeviceHandler) GetOfpPortInfo(device *voltha.Device, portNo int64) (*ic.PortCapability, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700372 cap := uint32(of.OfpPortFeatures_OFPPF_1GB_FD | of.OfpPortFeatures_OFPPF_FIBER)
373 return &ic.PortCapability{
374 Port: &voltha.LogicalPort{
375 OfpPort: &of.OfpPort{
376 HwAddr: macAddressToUint32Array(dh.device.MacAddress),
377 Config: 0,
378 State: uint32(of.OfpPortState_OFPPS_LIVE),
379 Curr: cap,
380 Advertised: cap,
381 Peer: cap,
382 CurrSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
383 MaxSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
384 },
385 DeviceId: dh.device.Id,
386 DevicePortNo: uint32(portNo),
387 },
388 }, nil
389}
390
391func (dh *DeviceHandler) omciIndication(omciInd *oop.OmciIndication) error {
392 log.Debugw("omci indication", log.Fields{"intfId": omciInd.IntfId, "onuId": omciInd.OnuId})
393
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400394 ponPort := IntfIdToPortNo(omciInd.GetIntfId(), voltha.Port_PON_OLT)
cuilin20187b2a8c32019-03-26 19:52:28 -0700395 kwargs := make(map[string]interface{})
396 kwargs["onu_id"] = omciInd.OnuId
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400397 kwargs["parent_port_no"] = ponPort
cuilin20187b2a8c32019-03-26 19:52:28 -0700398
399 if onuDevice, err := dh.coreProxy.GetChildDevice(nil, dh.device.Id, kwargs); err != nil {
400 log.Errorw("onu not found", log.Fields{"intfId": omciInd.IntfId, "onuId": omciInd.OnuId})
401 return err
402 } else {
403 omciMsg := &ic.InterAdapterOmciMessage{Message: omciInd.Pkt}
manikkaraj kbf256be2019-03-25 00:13:48 +0530404 if sendErr := dh.AdapterProxy.SendInterAdapterMessage(context.Background(), omciMsg,
cuilin20187b2a8c32019-03-26 19:52:28 -0700405 ic.InterAdapterMessageType_OMCI_REQUEST, dh.deviceType, onuDevice.Type,
406 onuDevice.Id, onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
407 log.Errorw("send omci request error", log.Fields{"fromAdapter": dh.deviceType, "toAdapter": onuDevice.Type, "onuId": onuDevice.Id, "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
408 return sendErr
409 }
410 return nil
411 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530412}
413
414// Process_inter_adapter_message process inter adater message
415func (dh *DeviceHandler) Process_inter_adapter_message(msg *ic.InterAdapterMessage) error {
cuilin20187b2a8c32019-03-26 19:52:28 -0700416 log.Debugw("Process_inter_adapter_message", log.Fields{"msgId": msg.Header.Id})
417 if msg.Header.Type == ic.InterAdapterMessageType_OMCI_REQUEST {
418 msgId := msg.Header.Id
419 fromTopic := msg.Header.FromTopic
420 toTopic := msg.Header.ToTopic
421 toDeviceId := msg.Header.ToDeviceId
422 proxyDeviceId := msg.Header.ProxyDeviceId
423
424 log.Debugw("omci request message header", log.Fields{"msgId": msgId, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceId": toDeviceId, "proxyDeviceId": proxyDeviceId})
425
426 msgBody := msg.GetBody()
427
428 omciMsg := &ic.InterAdapterOmciMessage{}
429 if err := ptypes.UnmarshalAny(msgBody, omciMsg); err != nil {
430 log.Warnw("cannot-unmarshal-omci-msg-body", log.Fields{"error": err})
431 return err
432 }
433
434 if onuDevice, err := dh.coreProxy.GetDevice(nil, dh.device.Id, toDeviceId); err != nil {
435 log.Errorw("onu not found", log.Fields{"onuDeviceId": toDeviceId, "error": err})
436 return err
437 } else {
438 dh.sendProxiedMessage(onuDevice, omciMsg)
439 }
440
441 } else {
442 log.Errorw("inter-adapter-unhandled-type", log.Fields{"msgType": msg.Header.Type})
443 }
444 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530445}
446
cuilin20187b2a8c32019-03-26 19:52:28 -0700447func (dh *DeviceHandler) sendProxiedMessage(onuDevice *voltha.Device, omciMsg *ic.InterAdapterOmciMessage) {
448 if onuDevice.ConnectStatus != voltha.ConnectStatus_REACHABLE {
449 log.Debugw("ONU is not reachable, cannot send OMCI", log.Fields{"serialNumber": onuDevice.SerialNumber, "intfId": onuDevice.ProxyAddress.GetChannelId(), "onuId": onuDevice.ProxyAddress.GetOnuId()})
450 return
451 }
452
453 omciMessage := &oop.OmciMsg{IntfId: onuDevice.ProxyAddress.GetChannelId(), OnuId: onuDevice.ProxyAddress.GetOnuId(), Pkt: omciMsg.Message}
454
manikkaraj kbf256be2019-03-25 00:13:48 +0530455 dh.Client.OmciMsgOut(context.Background(), omciMessage)
cuilin20187b2a8c32019-03-26 19:52:28 -0700456 log.Debugw("omci-message-sent", log.Fields{"serialNumber": onuDevice.SerialNumber, "intfId": onuDevice.ProxyAddress.GetChannelId(), "omciMsg": string(omciMsg.Message)})
457}
458
459func (dh *DeviceHandler) activateONU(intfId uint32, onuId int64, serialNum *oop.SerialNumber, serialNumber string) {
460 log.Debugw("activate-onu", log.Fields{"intfId": intfId, "onuId": onuId, "serialNum": serialNum, "serialNumber": serialNumber})
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400461 dh.flowMgr.UpdateOnuInfo(intfId, uint32(onuId), serialNumber)
cuilin20187b2a8c32019-03-26 19:52:28 -0700462 // TODO: need resource manager
463 var pir uint32 = 1000000
464 Onu := oop.Onu{IntfId: intfId, OnuId: uint32(onuId), SerialNumber: serialNum, Pir: pir}
manikkaraj kbf256be2019-03-25 00:13:48 +0530465 if _, err := dh.Client.ActivateOnu(context.Background(), &Onu); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700466 log.Errorw("activate-onu-failed", log.Fields{"Onu": Onu})
467 } else {
468 log.Infow("activated-onu", log.Fields{"SerialNumber": serialNumber})
469 }
470}
471
472func (dh *DeviceHandler) onuDiscIndication(onuDiscInd *oop.OnuDiscIndication, onuId uint32, sn string) error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400473 channelId := onuDiscInd.GetIntfId()
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400474 parentPortNo := IntfIdToPortNo(onuDiscInd.GetIntfId(), voltha.Port_PON_OLT)
manikkaraj kbf256be2019-03-25 00:13:48 +0530475 if err := dh.coreProxy.ChildDeviceDetected(nil, dh.device.Id, int(parentPortNo), "brcm_openomci_onu", int(channelId), string(onuDiscInd.SerialNumber.GetVendorId()), sn, int64(onuId)); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700476 log.Errorw("Create onu error", log.Fields{"parent_id": dh.device.Id, "ponPort": onuDiscInd.GetIntfId(), "onuId": onuId, "sn": sn, "error": err})
477 return err
478 }
479
480 kwargs := make(map[string]interface{})
481 kwargs["onu_id"] = onuId
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400482 kwargs["parent_port_no"] = parentPortNo
cuilin20187b2a8c32019-03-26 19:52:28 -0700483
484 for i := 0; i < 10; i++ {
485 if onuDevice, _ := dh.coreProxy.GetChildDevice(nil, dh.device.Id, kwargs); onuDevice != nil {
486 dh.activateONU(onuDiscInd.IntfId, int64(onuId), onuDiscInd.SerialNumber, sn)
487 return nil
488 } else {
489 time.Sleep(1 * time.Second)
490 log.Debugln("Sleep 1 seconds to active onu, retry times ", i+1)
491 }
492 }
493 log.Errorw("Cannot query onu, dont activate it.", log.Fields{"parent_id": dh.device.Id, "ponPort": onuDiscInd.GetIntfId(), "onuId": onuId, "sn": sn})
494 return errors.New("Failed to activate onu")
495}
496
497func (dh *DeviceHandler) onuIndication(onuInd *oop.OnuIndication) {
498 serialNumber := dh.stringifySerialNumber(onuInd.SerialNumber)
499
500 kwargs := make(map[string]interface{})
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400501 ponPort := IntfIdToPortNo(onuInd.GetIntfId(), voltha.Port_PON_OLT)
manikkaraj kbf256be2019-03-25 00:13:48 +0530502
cuilin20187b2a8c32019-03-26 19:52:28 -0700503 if serialNumber != "" {
504 kwargs["serial_number"] = serialNumber
505 } else {
506 kwargs["onu_id"] = onuInd.OnuId
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400507 kwargs["parent_port_no"] = ponPort
cuilin20187b2a8c32019-03-26 19:52:28 -0700508 }
509 if onuDevice, _ := dh.coreProxy.GetChildDevice(nil, dh.device.Id, kwargs); onuDevice != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400510 if onuDevice.ParentPortNo != ponPort {
cuilin20187b2a8c32019-03-26 19:52:28 -0700511 //log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": intfIdFromPortNo(onuDevice.ParentPortNo), "currentIntfId": onuInd.GetIntfId()})
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400512 log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": onuDevice.ParentPortNo, "currentIntfId": ponPort})
cuilin20187b2a8c32019-03-26 19:52:28 -0700513 }
514
515 if onuDevice.ProxyAddress.OnuId != onuInd.OnuId {
516 log.Warnw("ONU-id-mismatch, can happen if both voltha and the olt rebooted", log.Fields{"expected_onu_id": onuDevice.ProxyAddress.OnuId, "received_onu_id": onuInd.OnuId})
517 }
518
519 // adminState
520 if onuInd.AdminState == "down" {
521 if onuInd.OperState != "down" {
522 log.Errorw("ONU-admin-state-down-and-oper-status-not-down", log.Fields{"operState": onuInd.OperState})
523 // Forcing the oper state change code to execute
524 onuInd.OperState = "down"
525 }
526 // Port and logical port update is taken care of by oper state block
527 } else if onuInd.AdminState == "up" {
528 log.Debugln("received-onu-admin-state up")
529 } else {
530 log.Errorw("Invalid-or-not-implemented-admin-state", log.Fields{"received-admin-state": onuInd.AdminState})
531 }
532 log.Debugln("admin-state-dealt-with")
533
534 // operState
535 if onuInd.OperState == "down" {
536 if onuDevice.ConnectStatus != common.ConnectStatus_UNREACHABLE {
537 dh.coreProxy.DeviceStateUpdate(nil, onuDevice.Id, common.ConnectStatus_UNREACHABLE, onuDevice.OperStatus)
538 log.Debugln("onu-oper-state-is-down")
539 }
540 if onuDevice.OperStatus != common.OperStatus_DISCOVERED {
541 dh.coreProxy.DeviceStateUpdate(nil, onuDevice.Id, common.ConnectStatus_UNREACHABLE, common.OperStatus_DISCOVERED)
542 }
543 log.Debugw("inter-adapter-send-onu-ind", log.Fields{"onuIndication": onuInd})
544
545 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
manikkaraj kbf256be2019-03-25 00:13:48 +0530546 dh.AdapterProxy.SendInterAdapterMessage(nil, onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST, "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
cuilin20187b2a8c32019-03-26 19:52:28 -0700547 } else if onuInd.OperState == "up" {
548 if onuDevice.ConnectStatus != common.ConnectStatus_REACHABLE {
549 dh.coreProxy.DeviceStateUpdate(nil, onuDevice.Id, common.ConnectStatus_REACHABLE, onuDevice.OperStatus)
550
551 }
552 if onuDevice.OperStatus != common.OperStatus_DISCOVERED {
553 log.Warnw("ignore onu indication", log.Fields{"intfId": onuInd.IntfId, "onuId": onuInd.OnuId, "operStatus": onuDevice.OperStatus, "msgOperStatus": onuInd.OperState})
554 return
555 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530556 dh.AdapterProxy.SendInterAdapterMessage(nil, onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST, "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
cuilin20187b2a8c32019-03-26 19:52:28 -0700557 } else {
558 log.Warnw("Not-implemented-or-invalid-value-of-oper-state", log.Fields{"operState": onuInd.OperState})
559 }
560 } else {
561 log.Errorw("onu not found", log.Fields{"intfId": onuInd.IntfId, "onuId": onuInd.OnuId})
562 return
563 }
564
565}
566
567func (dh *DeviceHandler) stringifySerialNumber(serialNum *oop.SerialNumber) string {
568 if serialNum != nil {
569 return string(serialNum.VendorId) + dh.stringifyVendorSpecific(serialNum.VendorSpecific)
570 } else {
571 return ""
572 }
573}
574
575func (dh *DeviceHandler) stringifyVendorSpecific(vendorSpecific []byte) string {
576 tmp := fmt.Sprintf("%x", (uint32(vendorSpecific[0])>>4)&0x0f) +
577 fmt.Sprintf("%x", (uint32(vendorSpecific[0]&0x0f))) +
578 fmt.Sprintf("%x", (uint32(vendorSpecific[1])>>4)&0x0f) +
579 fmt.Sprintf("%x", (uint32(vendorSpecific[1]))&0x0f) +
580 fmt.Sprintf("%x", (uint32(vendorSpecific[2])>>4)&0x0f) +
581 fmt.Sprintf("%x", (uint32(vendorSpecific[2]))&0x0f) +
582 fmt.Sprintf("%x", (uint32(vendorSpecific[3])>>4)&0x0f) +
583 fmt.Sprintf("%x", (uint32(vendorSpecific[3]))&0x0f)
584 return tmp
585}
586
587// flows
588func (dh *DeviceHandler) Update_flows_bulk() error {
589 return errors.New("UnImplemented")
590}
Girish Gowdru0c588b22019-04-23 23:24:56 -0400591func (dh *DeviceHandler) GetChildDevice(parentPort uint32, onuId uint32) *voltha.Device {
592 log.Debugw("GetChildDevice", log.Fields{"pon port": parentPort, "onuId": onuId})
593 kwargs := make(map[string]interface{})
594 kwargs["onu_id"] = onuId
595 kwargs["parent_port_no"] = parentPort
596 onuDevice, err := dh.coreProxy.GetChildDevice(nil, dh.device.Id, kwargs)
597 if err != nil {
598 log.Errorw("onu not found", log.Fields{"intfId": parentPort, "onuId": onuId})
599 return nil
600 }
601 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
602 return onuDevice
manikkaraj kbf256be2019-03-25 00:13:48 +0530603}
604
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400605func (dh *DeviceHandler) SendPacketInToCore(logicalPort uint32, packetPayload []byte) {
606 log.Debugw("SendPacketInToCore", log.Fields{"port": logicalPort, "packetPayload": packetPayload})
607 if err := dh.coreProxy.SendPacketIn(nil, dh.device.Id, logicalPort, packetPayload); err != nil {
608 log.Errorw("Error sending packetin to core", log.Fields{"error": err})
609 return
610 }
611 log.Debug("Sent packet-in to core successfully")
612}
613
manikkaraj kbf256be2019-03-25 00:13:48 +0530614func (dh *DeviceHandler) UpdateFlowsIncrementally(device *voltha.Device, flows *of.FlowChanges, groups *of.FlowGroupChanges) error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400615 log.Debugw("In UpdateFlowsIncrementally", log.Fields{"deviceId": device.Id, "flows": flows, "groups": groups})
616 if flows != nil {
617 for _, flow := range flows.ToAdd.Items {
618 dh.flowMgr.AddFlow(flow)
619 }
620 }
621 if groups != nil {
622 for _, flow := range flows.ToRemove.Items {
623 log.Debug("Removing flow", log.Fields{"deviceId": device.Id, "flowToRemove": flow})
624 // dh.flowMgr.RemoveFlow(flow)
625 }
626 }
627 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530628}
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400629
630func (dh *DeviceHandler) DisableDevice(device *voltha.Device) error {
631 if _, err := dh.Client.DisableOlt(context.Background(), new(oop.Empty)); err != nil {
632 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
633 return err
634 }
635 dh.lockDevice.Lock()
636 dh.adminState = "down"
637 dh.lockDevice.Unlock()
638 log.Debug("olt-disabled")
639
640 cloned := proto.Clone(device).(*voltha.Device)
641 // Update the all ports state on that device to disable
642 if err := dh.coreProxy.PortsStateUpdate(nil, cloned.Id, voltha.OperStatus_UNKNOWN); err != nil {
643 log.Errorw("updating-ports-failed", log.Fields{"deviceId": device.Id, "error": err})
644 return err
645 }
646
647 //Update the device oper state
648 cloned.OperStatus = voltha.OperStatus_UNKNOWN
649 dh.device = cloned
650
651 if err := dh.coreProxy.DeviceStateUpdate(nil, cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
652 log.Errorw("error-updating-device-state", log.Fields{"deviceId": device.Id, "error": err})
653 return err
654 }
655 log.Debugw("DisableDevice-end", log.Fields{"deviceId": device.Id})
656 return nil
657}
658
659func (dh *DeviceHandler) ReenableDevice(device *voltha.Device) error {
660 if _, err := dh.Client.ReenableOlt(context.Background(), new(oop.Empty)); err != nil {
661 log.Errorw("Failed to reenable olt ", log.Fields{"err": err})
662 return err
663 }
664
665 dh.lockDevice.Lock()
666 dh.adminState = "up"
667 dh.lockDevice.Unlock()
668 log.Debug("olt-reenabled")
669
670 cloned := proto.Clone(device).(*voltha.Device)
671 // Update the all ports state on that device to enable
672 if err := dh.coreProxy.PortsStateUpdate(nil, cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
673 log.Errorw("updating-ports-failed", log.Fields{"deviceId": device.Id, "error": err})
674 return err
675 }
676
677 //Update the device oper status as ACTIVE
678 cloned.OperStatus = voltha.OperStatus_ACTIVE
679 dh.device = cloned
680
681 if err := dh.coreProxy.DeviceStateUpdate(nil, cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
682 log.Errorw("error-updating-device-state", log.Fields{"deviceId": device.Id, "error": err})
683 return err
684 }
685 log.Debugw("ReEnableDevice-end", log.Fields{"deviceId": device.Id})
686
687 return nil
688}
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400689
690func (dh *DeviceHandler) handlePacketIndication(packetIn *oop.PacketIndication) {
691 log.Debugw("Received packet-in", log.Fields{"packet-indication": *packetIn})
692 logicalPortNum, err := dh.flowMgr.GetLogicalPortFromPacketIn(packetIn)
693 if err != nil {
694 log.Errorw("Error getting logical port from packet-in", log.Fields{"error": err})
695 return
696 }
697 log.Debugw("sending packet-in to core", log.Fields{"logicalPortNum": logicalPortNum, "packet": *packetIn})
698 if err := dh.coreProxy.SendPacketIn(nil, dh.device.Id, logicalPortNum, packetIn.Pkt); err != nil {
699 log.Errorw("Error sending packet-in to core", log.Fields{"error": err})
700 return
701 }
702 log.Debug("Success sending packet-in to core!")
703}
704
705func (dh *DeviceHandler) PacketOut(egress_port_no int, packet *of.OfpPacketOut) error {
706 log.Debugw("PacketOut", log.Fields{"deviceId": dh.deviceId, "egress_port_no": egress_port_no, "pkt-length": len(packet.Data)})
707 var etherFrame ethernet.Frame
708 err := (&etherFrame).UnmarshalBinary(packet.Data)
709 if err != nil {
710 log.Errorw("Failed to unmarshal into ethernet frame", log.Fields{"err": err, "pkt-length": len(packet.Data)})
711 return err
712 }
713 log.Debugw("Ethernet Frame", log.Fields{"Frame": etherFrame})
714 egressPortType := IntfIdToPortTypeName(uint32(egress_port_no))
715 if egressPortType == voltha.Port_ETHERNET_UNI {
716 if etherFrame.VLAN != nil { // If double tag, remove the outer tag
717 nextEthType := (uint16(packet.Data[16]) << 8) | uint16(packet.Data[17])
718 if nextEthType == 0x8100 {
719 etherFrame.VLAN = nil
720 packet.Data, err = etherFrame.MarshalBinary()
721 if err != nil {
722 log.Fatalf("failed to marshal frame: %v", err)
723 return err
724 }
725 if err := (&etherFrame).UnmarshalBinary(packet.Data); err != nil {
726 log.Fatalf("failed to unmarshal frame: %v", err)
727 return err
728 }
729 log.Debug("Double tagged packet , removed outer vlan", log.Fields{"New frame": etherFrame})
730 }
731 }
732 intfId := IntfIdFromUniPortNum(uint32(egress_port_no))
733 onuId := OnuIdFromPortNum(uint32(egress_port_no))
734 uniId := UniIdFromPortNum(uint32(egress_port_no))
735 /*gemPortId, err := dh.flowMgr.GetPacketOutGemPortId(intfId, onuId, uint32(egress_port_no))
736 if err != nil{
737 log.Errorw("Error while getting gemport to packet-out",log.Fields{"error": err})
738 return err
739 }*/
740 onuPkt := oop.OnuPacket{IntfId: intfId, OnuId: onuId, PortNo: uint32(egress_port_no), Pkt: packet.Data}
741 log.Debug("sending-packet-to-ONU", log.Fields{"egress_port_no": egress_port_no, "IntfId": intfId, "onuId": onuId,
742 "uniId": uniId, "packet": packet.Data})
743 if _, err := dh.Client.OnuPacketOut(context.Background(), &onuPkt); err != nil {
744 log.Errorw("Error while sending packet-out to ONU", log.Fields{"error": err})
745 return err
746 }
747 } else if egressPortType == voltha.Port_ETHERNET_NNI {
748 uplinkPkt := oop.UplinkPacket{IntfId: IntfIdFromNniPortNum(uint32(egress_port_no)), Pkt: packet.Data}
749 log.Debug("sending-packet-to-uplink", log.Fields{"uplink_pkt": uplinkPkt})
750 if _, err := dh.Client.UplinkPacketOut(context.Background(), &uplinkPkt); err != nil {
751 log.Errorw("Error while sending packet-out to uplink", log.Fields{"error": err})
752 return err
753 }
754 } else {
755 log.Warnw("Packet-out-to-this-interface-type-not-implemented", log.Fields{"egress_port_no": egress_port_no, "egressPortType": egressPortType})
756 }
757 return nil
758}