blob: 3053f2ade0dd9fda610406d54b4450fbd3eb87e9 [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 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070016
17//Package adaptercore provides the utility for olt devices, flows and statistics
Phaneendra Manda4c62c802019-03-06 21:37:49 +053018package adaptercore
19
20import (
cuilin20187b2a8c32019-03-26 19:52:28 -070021 "context"
Matt Jeanneret1359c732019-08-01 21:40:02 -040022 "encoding/hex"
cuilin20187b2a8c32019-03-26 19:52:28 -070023 "errors"
24 "fmt"
25 "io"
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -040026 "net"
cuilin20187b2a8c32019-03-26 19:52:28 -070027 "strconv"
28 "strings"
29 "sync"
30 "time"
Phaneendra Manda4c62c802019-03-06 21:37:49 +053031
Chaitrashree G Sb2b62dd2019-07-24 21:47:04 -040032 "google.golang.org/grpc/codes"
33
cuilin20187b2a8c32019-03-26 19:52:28 -070034 "github.com/gogo/protobuf/proto"
35 "github.com/golang/protobuf/ptypes"
Scott Baker51290152019-10-24 14:23:20 -070036 "github.com/opencord/voltha-lib-go/v2/pkg/adapters/adapterif"
37 "github.com/opencord/voltha-lib-go/v2/pkg/log"
Girish Gowdru0c588b22019-04-23 23:24:56 -040038 rsrcMgr "github.com/opencord/voltha-openolt-adapter/adaptercore/resourcemanager"
manikkaraj kbf256be2019-03-25 00:13:48 +053039 "github.com/opencord/voltha-protos/go/common"
40 ic "github.com/opencord/voltha-protos/go/inter_container"
41 of "github.com/opencord/voltha-protos/go/openflow_13"
42 oop "github.com/opencord/voltha-protos/go/openolt"
manikkaraj kbf256be2019-03-25 00:13:48 +053043 "github.com/opencord/voltha-protos/go/voltha"
cuilin20187b2a8c32019-03-26 19:52:28 -070044 "google.golang.org/grpc"
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -040045 "google.golang.org/grpc/status"
Phaneendra Manda4c62c802019-03-06 21:37:49 +053046)
47
salmansiddiqui7ac62132019-08-22 03:58:50 +000048// Constants for number of retries and for timeout
Manikkaraj kb1d51442019-07-23 10:41:02 -040049const (
salmansiddiqui7ac62132019-08-22 03:58:50 +000050 MaxRetry = 10
51 MaxTimeOutInMs = 500
Manikkaraj kb1d51442019-07-23 10:41:02 -040052)
53
kdarapu381c6902019-07-31 18:23:16 +053054func init() {
55 _, _ = log.AddPackage(log.JSON, log.DebugLevel, nil)
56}
57
Phaneendra Manda4c62c802019-03-06 21:37:49 +053058//DeviceHandler will interact with the OLT device.
59type DeviceHandler struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070060 deviceID string
cuilin20187b2a8c32019-03-26 19:52:28 -070061 deviceType string
Girish Gowdru5ba46c92019-04-25 05:00:05 -040062 adminState string
cuilin20187b2a8c32019-03-26 19:52:28 -070063 device *voltha.Device
kdarapu381c6902019-07-31 18:23:16 +053064 coreProxy adapterif.CoreProxy
65 AdapterProxy adapterif.AdapterProxy
66 EventProxy adapterif.EventProxy
cuilin20187b2a8c32019-03-26 19:52:28 -070067 openOLT *OpenOLT
cuilin20187b2a8c32019-03-26 19:52:28 -070068 exitChannel chan int
69 lockDevice sync.RWMutex
manikkaraj kbf256be2019-03-25 00:13:48 +053070 Client oop.OpenoltClient
cuilin20187b2a8c32019-03-26 19:52:28 -070071 transitionMap *TransitionMap
72 clientCon *grpc.ClientConn
manikkaraj kbf256be2019-03-25 00:13:48 +053073 flowMgr *OpenOltFlowMgr
Devmalya Paulfb990a52019-07-09 10:01:49 -040074 eventMgr *OpenOltEventMgr
manikkaraj kbf256be2019-03-25 00:13:48 +053075 resourceMgr *rsrcMgr.OpenOltResourceMgr
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -040076 discOnus map[string]bool
Mahir Gunyela3f9add2019-06-06 15:13:19 -070077 onus map[string]*OnuDevice
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070078 nniIntfID int
Mahir Gunyela3f9add2019-06-06 15:13:19 -070079}
80
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070081//OnuDevice represents ONU related info
Mahir Gunyela3f9add2019-06-06 15:13:19 -070082type OnuDevice struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070083 deviceID string
Mahir Gunyela3f9add2019-06-06 15:13:19 -070084 deviceType string
85 serialNumber string
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070086 onuID uint32
87 intfID uint32
88 proxyDeviceID string
A R Karthick1f85b802019-10-11 05:06:05 +000089 uniPorts map[uint32]struct{}
Mahir Gunyela3f9add2019-06-06 15:13:19 -070090}
91
92//NewOnuDevice creates a new Onu Device
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070093func NewOnuDevice(devID, deviceTp, serialNum string, onuID, intfID uint32, proxyDevID string) *OnuDevice {
Mahir Gunyela3f9add2019-06-06 15:13:19 -070094 var device OnuDevice
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070095 device.deviceID = devID
Mahir Gunyela3f9add2019-06-06 15:13:19 -070096 device.deviceType = deviceTp
97 device.serialNumber = serialNum
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070098 device.onuID = onuID
99 device.intfID = intfID
100 device.proxyDeviceID = proxyDevID
A R Karthick1f85b802019-10-11 05:06:05 +0000101 device.uniPorts = make(map[uint32]struct{})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700102 return &device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530103}
104
105//NewDeviceHandler creates a new device handler
kdarapu381c6902019-07-31 18:23:16 +0530106func NewDeviceHandler(cp adapterif.CoreProxy, ap adapterif.AdapterProxy, ep adapterif.EventProxy, device *voltha.Device, adapter *OpenOLT) *DeviceHandler {
cuilin20187b2a8c32019-03-26 19:52:28 -0700107 var dh DeviceHandler
108 dh.coreProxy = cp
Girish Gowdru0c588b22019-04-23 23:24:56 -0400109 dh.AdapterProxy = ap
Devmalya Paulfb990a52019-07-09 10:01:49 -0400110 dh.EventProxy = ep
cuilin20187b2a8c32019-03-26 19:52:28 -0700111 cloned := (proto.Clone(device)).(*voltha.Device)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700112 dh.deviceID = cloned.Id
cuilin20187b2a8c32019-03-26 19:52:28 -0700113 dh.deviceType = cloned.Type
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400114 dh.adminState = "up"
cuilin20187b2a8c32019-03-26 19:52:28 -0700115 dh.device = cloned
116 dh.openOLT = adapter
117 dh.exitChannel = make(chan int, 1)
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400118 dh.discOnus = make(map[string]bool)
cuilin20187b2a8c32019-03-26 19:52:28 -0700119 dh.lockDevice = sync.RWMutex{}
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700120 dh.onus = make(map[string]*OnuDevice)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700121 // The nniIntfID is initialized to -1 (invalid) and set to right value
Girish Gowdru1110ef22019-06-24 11:17:59 -0400122 // when the first IntfOperInd with status as "up" is received for
123 // any one of the available NNI port on the OLT device.
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700124 dh.nniIntfID = -1
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530125
cuilin20187b2a8c32019-03-26 19:52:28 -0700126 //TODO initialize the support classes.
127 return &dh
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530128}
129
130// start save the device to the data model
131func (dh *DeviceHandler) start(ctx context.Context) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700132 dh.lockDevice.Lock()
133 defer dh.lockDevice.Unlock()
134 log.Debugw("starting-device-agent", log.Fields{"device": dh.device})
135 // Add the initial device to the local model
136 log.Debug("device-agent-started")
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530137}
138
139// stop stops the device dh. Not much to do for now
140func (dh *DeviceHandler) stop(ctx context.Context) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700141 dh.lockDevice.Lock()
142 defer dh.lockDevice.Unlock()
143 log.Debug("stopping-device-agent")
144 dh.exitChannel <- 1
145 log.Debug("device-agent-stopped")
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530146}
147
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400148func macifyIP(ip net.IP) string {
149 if len(ip) > 0 {
150 oct1 := strconv.FormatInt(int64(ip[12]), 16)
151 oct2 := strconv.FormatInt(int64(ip[13]), 16)
152 oct3 := strconv.FormatInt(int64(ip[14]), 16)
153 oct4 := strconv.FormatInt(int64(ip[15]), 16)
154 return fmt.Sprintf("00:00:%02v:%02v:%02v:%02v", oct1, oct2, oct3, oct4)
155 }
156 return ""
157}
158
159func generateMacFromHost(host string) (string, error) {
160 var genmac string
161 var addr net.IP
162 var ips []string
163 var err error
164
165 log.Debugw("generating-mac-from-host", log.Fields{"host": host})
166
167 if addr = net.ParseIP(host); addr == nil {
168 log.Debugw("looking-up-hostname", log.Fields{"host": host})
169
170 if ips, err = net.LookupHost(host); err == nil {
171 log.Debugw("dns-result-ips", log.Fields{"ips": ips})
172 if addr = net.ParseIP(ips[0]); addr == nil {
173 log.Errorw("unable-to-parse-ip", log.Fields{"ip": ips[0]})
174 return "", errors.New("unable-to-parse-ip")
175 }
176 genmac = macifyIP(addr)
177 log.Debugw("using-ip-as-mac", log.Fields{"host": ips[0], "mac": genmac})
178 return genmac, nil
179 }
180 log.Errorw("cannot-resolve-hostname-to-ip", log.Fields{"host": host})
181 return "", err
182 }
183
184 genmac = macifyIP(addr)
185 log.Debugw("using-ip-as-mac", log.Fields{"host": host, "mac": genmac})
186 return genmac, nil
187}
188
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530189func macAddressToUint32Array(mac string) []uint32 {
cuilin20187b2a8c32019-03-26 19:52:28 -0700190 slist := strings.Split(mac, ":")
191 result := make([]uint32, len(slist))
192 var err error
193 var tmp int64
194 for index, val := range slist {
195 if tmp, err = strconv.ParseInt(val, 16, 32); err != nil {
196 return []uint32{1, 2, 3, 4, 5, 6}
197 }
198 result[index] = uint32(tmp)
199 }
200 return result
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530201}
202
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700203//GetportLabel returns the label for the NNI and the PON port based on port number and port type
manikkaraj kbf256be2019-03-25 00:13:48 +0530204func GetportLabel(portNum uint32, portType voltha.Port_PortType) string {
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530205
Girish Gowdru0c588b22019-04-23 23:24:56 -0400206 if portType == voltha.Port_ETHERNET_NNI {
207 return fmt.Sprintf("nni-%d", portNum)
208 } else if portType == voltha.Port_PON_OLT {
209 return fmt.Sprintf("pon-%d", portNum)
cuilin20187b2a8c32019-03-26 19:52:28 -0700210 } else if portType == voltha.Port_ETHERNET_UNI {
211 log.Errorw("local UNI management not supported", log.Fields{})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400212 return ""
cuilin20187b2a8c32019-03-26 19:52:28 -0700213 }
214 return ""
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530215}
216
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700217func (dh *DeviceHandler) addPort(intfID uint32, portType voltha.Port_PortType, state string) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700218 var operStatus common.OperStatus_OperStatus
219 if state == "up" {
220 operStatus = voltha.OperStatus_ACTIVE
221 } else {
222 operStatus = voltha.OperStatus_DISCOVERED
223 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700224 portNum := IntfIDToPortNo(intfID, portType)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400225 label := GetportLabel(portNum, portType)
226 if len(label) == 0 {
227 log.Errorw("Invalid-port-label", log.Fields{"portNum": portNum, "portType": portType})
228 return
229 }
230 // Now create Port
231 port := &voltha.Port{
cuilin20187b2a8c32019-03-26 19:52:28 -0700232 PortNo: portNum,
233 Label: label,
234 Type: portType,
235 OperStatus: operStatus,
236 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400237 log.Debugw("Sending port update to core", log.Fields{"port": port})
cuilin20187b2a8c32019-03-26 19:52:28 -0700238 // Synchronous call to update device - this method is run in its own go routine
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700239 if err := dh.coreProxy.PortCreated(context.TODO(), dh.device.Id, port); err != nil {
240 log.Errorw("error-creating-nni-port", log.Fields{"deviceID": dh.device.Id, "portType": portType, "error": err})
Girish Gowdru1110ef22019-06-24 11:17:59 -0400241 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700242
Girish Gowdru1110ef22019-06-24 11:17:59 -0400243 // Once we have successfully added the NNI port to the core, if the
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700244 // locally cached nniIntfID is set to invalid (-1), set it to the right value.
245 if portType == voltha.Port_ETHERNET_NNI && dh.nniIntfID == -1 {
246 dh.nniIntfID = int(intfID)
cuilin20187b2a8c32019-03-26 19:52:28 -0700247 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530248}
249
250// readIndications to read the indications from the OLT device
251func (dh *DeviceHandler) readIndications() {
William Kurkianff524662019-08-20 10:34:30 -0400252 defer log.Errorw("Indications ended", log.Fields{})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400253 indications, err := dh.Client.EnableIndication(context.Background(), new(oop.Empty))
cuilin20187b2a8c32019-03-26 19:52:28 -0700254 if err != nil {
255 log.Errorw("Failed to read indications", log.Fields{"err": err})
256 return
257 }
258 if indications == nil {
259 log.Errorw("Indications is nil", log.Fields{})
260 return
261 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400262 /* get device state */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700263 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400264 if err != nil || device == nil {
265 /*TODO: needs to handle error scenarios */
266 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700267 return
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400268 }
269 // When the device is in DISABLED and Adapter container restarts, we need to
270 // rebuild the locally maintained admin state.
271 if device.AdminState == voltha.AdminState_DISABLED {
272 dh.lockDevice.Lock()
273 dh.adminState = "down"
274 dh.lockDevice.Unlock()
275 }
276
cuilin20187b2a8c32019-03-26 19:52:28 -0700277 for {
278 indication, err := indications.Recv()
279 if err == io.EOF {
280 break
281 }
282 if err != nil {
283 log.Infow("Failed to read from indications", log.Fields{"err": err})
Devmalya Paul495b94a2019-08-27 19:42:00 -0400284 if dh.adminState == "deleted" {
285 log.Debug("Device deleted stoping the read indication thread")
286 break
287 }
Girish Gowdrud4245152019-05-10 00:47:31 -0400288 dh.transitionMap.Handle(DeviceDownInd)
289 dh.transitionMap.Handle(DeviceInit)
290 break
cuilin20187b2a8c32019-03-26 19:52:28 -0700291 }
Chaitrashree G S44124192019-08-07 20:21:36 -0400292 dh.lockDevice.RLock()
293 adminState := dh.adminState
294 dh.lockDevice.RUnlock()
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400295 // When OLT is admin down, allow only NNI operation status change indications.
Chaitrashree G S44124192019-08-07 20:21:36 -0400296 if adminState == "down" {
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400297 _, isIntfOperInd := indication.Data.(*oop.Indication_IntfOperInd)
298 if isIntfOperInd {
299 intfOperInd := indication.GetIntfOperInd()
300 if intfOperInd.GetType() == "nni" {
301 log.Infow("olt is admin down, allow nni ind", log.Fields{})
302 }
303 } else {
304 log.Infow("olt is admin down, ignore indication", log.Fields{})
305 continue
306 }
307 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530308
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700309 dh.handleIndication(indication)
manikkaraj kbf256be2019-03-25 00:13:48 +0530310
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700311 }
312}
313
314func (dh *DeviceHandler) handleOltIndication(oltIndication *oop.OltIndication) {
Daniele Rossi051466a2019-07-26 13:39:37 +0000315 raisedTs := time.Now().UnixNano()
Gamze Abakaa1a50522019-10-03 19:28:27 +0000316 if oltIndication.OperState == "up" && dh.transitionMap.currentDeviceState != deviceStateUp {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700317 dh.transitionMap.Handle(DeviceUpInd)
318 } else if oltIndication.OperState == "down" {
319 dh.transitionMap.Handle(DeviceDownInd)
320 }
Daniele Rossi051466a2019-07-26 13:39:37 +0000321 // Send or clear Alarm
322 dh.eventMgr.oltUpDownIndication(oltIndication, dh.deviceID, raisedTs)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700323}
324
325func (dh *DeviceHandler) handleIndication(indication *oop.Indication) {
Devmalya Paulfb990a52019-07-09 10:01:49 -0400326 raisedTs := time.Now().UnixNano()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700327 switch indication.Data.(type) {
328 case *oop.Indication_OltInd:
329 dh.handleOltIndication(indication.GetOltInd())
330 case *oop.Indication_IntfInd:
331 intfInd := indication.GetIntfInd()
332 go dh.addPort(intfInd.GetIntfId(), voltha.Port_PON_OLT, intfInd.GetOperState())
333 log.Infow("Received interface indication ", log.Fields{"InterfaceInd": intfInd})
334 case *oop.Indication_IntfOperInd:
335 intfOperInd := indication.GetIntfOperInd()
336 if intfOperInd.GetType() == "nni" {
337 go dh.addPort(intfOperInd.GetIntfId(), voltha.Port_ETHERNET_NNI, intfOperInd.GetOperState())
338 } else if intfOperInd.GetType() == "pon" {
339 // TODO: Check what needs to be handled here for When PON PORT down, ONU will be down
340 // Handle pon port update
Gamze Abaka8539e202019-10-03 19:22:48 +0000341 go dh.addPort(intfOperInd.GetIntfId(), voltha.Port_PON_OLT, intfOperInd.GetOperState())
cuilin20187b2a8c32019-03-26 19:52:28 -0700342 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700343 log.Infow("Received interface oper indication ", log.Fields{"InterfaceOperInd": intfOperInd})
344 case *oop.Indication_OnuDiscInd:
345 onuDiscInd := indication.GetOnuDiscInd()
346 log.Infow("Received Onu discovery indication ", log.Fields{"OnuDiscInd": onuDiscInd})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700347 sn := dh.stringifySerialNumber(onuDiscInd.SerialNumber)
Matt Jeanneret53539512019-07-20 14:47:02 -0400348 go dh.onuDiscIndication(onuDiscInd, sn)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700349 case *oop.Indication_OnuInd:
350 onuInd := indication.GetOnuInd()
351 log.Infow("Received Onu indication ", log.Fields{"OnuInd": onuInd})
352 go dh.onuIndication(onuInd)
353 case *oop.Indication_OmciInd:
354 omciInd := indication.GetOmciInd()
355 log.Infow("Received Omci indication ", log.Fields{"OmciInd": omciInd})
William Kurkianff524662019-08-20 10:34:30 -0400356 go dh.omciIndication(omciInd)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700357 case *oop.Indication_PktInd:
358 pktInd := indication.GetPktInd()
359 log.Infow("Received pakcet indication ", log.Fields{"PktInd": pktInd})
360 go dh.handlePacketIndication(pktInd)
361 case *oop.Indication_PortStats:
362 portStats := indication.GetPortStats()
363 log.Infow("Received port stats indication", log.Fields{"PortStats": portStats})
364 case *oop.Indication_FlowStats:
365 flowStats := indication.GetFlowStats()
366 log.Infow("Received flow stats", log.Fields{"FlowStats": flowStats})
367 case *oop.Indication_AlarmInd:
368 alarmInd := indication.GetAlarmInd()
369 log.Infow("Received alarm indication ", log.Fields{"AlarmInd": alarmInd})
Devmalya Paulfb990a52019-07-09 10:01:49 -0400370 dh.eventMgr.ProcessEvents(alarmInd, dh.deviceID, raisedTs)
371
cuilin20187b2a8c32019-03-26 19:52:28 -0700372 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530373}
374
375// doStateUp handle the olt up indication and update to voltha core
376func (dh *DeviceHandler) doStateUp() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400377 // Synchronous call to update device state - this method is run in its own go routine
cuilin20187b2a8c32019-03-26 19:52:28 -0700378 if err := dh.coreProxy.DeviceStateUpdate(context.Background(), dh.device.Id, voltha.ConnectStatus_REACHABLE,
Girish Gowdru0c588b22019-04-23 23:24:56 -0400379 voltha.OperStatus_ACTIVE); err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700380 log.Errorw("Failed to update device with OLT UP indication", log.Fields{"deviceID": dh.device.Id, "error": err})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400381 return err
382 }
383 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530384}
385
386// doStateDown handle the olt down indication
387func (dh *DeviceHandler) doStateDown() error {
serkant.uluderya245caba2019-09-24 23:15:29 -0700388 dh.lockDevice.Lock()
389 defer dh.lockDevice.Unlock()
Girish Gowdrud4245152019-05-10 00:47:31 -0400390 log.Debug("do-state-down-start")
391
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700392 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400393 if err != nil || device == nil {
394 /*TODO: needs to handle error scenarios */
395 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700396 return errors.New("failed to fetch device device")
Girish Gowdrud4245152019-05-10 00:47:31 -0400397 }
398
399 cloned := proto.Clone(device).(*voltha.Device)
400 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700401 if er := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); er != nil {
402 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": er})
403 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400404 }
405
406 //Update the device oper state and connection status
407 cloned.OperStatus = voltha.OperStatus_UNKNOWN
408 cloned.ConnectStatus = common.ConnectStatus_UNREACHABLE
409 dh.device = cloned
410
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700411 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
412 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": er})
413 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400414 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400415
416 //get the child device for the parent device
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700417 onuDevices, err := dh.coreProxy.GetChildDevices(context.TODO(), dh.device.Id)
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400418 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700419 log.Errorw("failed to get child devices information", log.Fields{"deviceID": dh.device.Id, "error": err})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400420 return err
421 }
422 for _, onuDevice := range onuDevices.Items {
423
424 // Update onu state as down in onu adapter
425 onuInd := oop.OnuIndication{}
426 onuInd.OperState = "down"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700427 er := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), &onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
428 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
429 if er != nil {
430 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
431 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
serkant.uluderya245caba2019-09-24 23:15:29 -0700432 //Do not return here and continue to process other ONUs
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700433 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400434 }
serkant.uluderya245caba2019-09-24 23:15:29 -0700435 /* Discovered ONUs entries need to be cleared , since after OLT
436 is up, it starts sending discovery indications again*/
437 dh.discOnus = make(map[string]bool)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700438 log.Debugw("do-state-down-end", log.Fields{"deviceID": device.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700439 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530440}
441
442// doStateInit dial the grpc before going to init state
443func (dh *DeviceHandler) doStateInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400444 var err error
Girish Gowdrud4245152019-05-10 00:47:31 -0400445 dh.clientCon, err = grpc.Dial(dh.device.GetHostAndPort(), grpc.WithInsecure(), grpc.WithBlock())
Girish Gowdru0c588b22019-04-23 23:24:56 -0400446 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700447 log.Errorw("Failed to dial device", log.Fields{"DeviceId": dh.deviceID, "HostAndPort": dh.device.GetHostAndPort(), "err": err})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400448 return err
449 }
450 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530451}
452
453// postInit create olt client instance to invoke RPC on the olt device
454func (dh *DeviceHandler) postInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400455 dh.Client = oop.NewOpenoltClient(dh.clientCon)
456 dh.transitionMap.Handle(GrpcConnected)
457 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530458}
459
460// doStateConnected get the device info and update to voltha core
461func (dh *DeviceHandler) doStateConnected() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400462 log.Debug("OLT device has been connected")
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400463
464 // Case where OLT is disabled and then rebooted.
465 if dh.adminState == "down" {
466 log.Debugln("do-state-connected--device-admin-state-down")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700467 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400468 if err != nil || device == nil {
469 /*TODO: needs to handle error scenarios */
470 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
471 }
472
473 cloned := proto.Clone(device).(*voltha.Device)
474 cloned.ConnectStatus = voltha.ConnectStatus_REACHABLE
475 cloned.OperStatus = voltha.OperStatus_UNKNOWN
476 dh.device = cloned
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700477 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
478 log.Errorw("error-updating-device-state", log.Fields{"deviceID": dh.device.Id, "error": er})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400479 }
480
Chaitrashree G S44124192019-08-07 20:21:36 -0400481 // Since the device was disabled before the OLT was rebooted, enforce the OLT to be Disabled after re-connection.
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400482 _, err = dh.Client.DisableOlt(context.Background(), new(oop.Empty))
483 if err != nil {
484 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
485 }
486
487 // Start reading indications
488 go dh.readIndications()
489 return nil
490 }
491
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400492 deviceInfo, err := dh.populateDeviceInfo()
cuilin20187b2a8c32019-03-26 19:52:28 -0700493 if err != nil {
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400494 log.Errorw("Unable to populate Device Info", log.Fields{"err": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700495 return err
496 }
Girish Gowdrud4245152019-05-10 00:47:31 -0400497
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700498 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400499 if err != nil || device == nil {
500 /*TODO: needs to handle error scenarios */
501 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700502 return err
Girish Gowdrud4245152019-05-10 00:47:31 -0400503 }
504 cloned := proto.Clone(device).(*voltha.Device)
505 // Update the all ports (if available) on that device to ACTIVE.
506 // The ports do not normally exist, unless the device is coming back from a reboot
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700507 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
508 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdrud4245152019-05-10 00:47:31 -0400509 return err
510 }
511
Girish Gowdru0c588b22019-04-23 23:24:56 -0400512 KVStoreHostPort := fmt.Sprintf("%s:%d", dh.openOLT.KVStoreHost, dh.openOLT.KVStorePort)
513 // Instantiate resource manager
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700514 if dh.resourceMgr = rsrcMgr.NewResourceMgr(dh.deviceID, KVStoreHostPort, dh.openOLT.KVStoreType, dh.deviceType, deviceInfo); dh.resourceMgr == nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400515 log.Error("Error while instantiating resource manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700516 return errors.New("instantiating resource manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400517 }
518 // Instantiate flow manager
519 if dh.flowMgr = NewFlowManager(dh, dh.resourceMgr); dh.flowMgr == nil {
520 log.Error("Error while instantiating flow manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700521 return errors.New("instantiating flow manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400522 }
523 /* TODO: Instantiate Alarm , stats , BW managers */
Devmalya Paulfb990a52019-07-09 10:01:49 -0400524 /* Instantiating Event Manager to handle Alarms and KPIs */
Devmalya Paul90ca3012019-09-02 21:55:45 -0400525 dh.eventMgr = NewEventMgr(dh.EventProxy, dh)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530526
cuilin20187b2a8c32019-03-26 19:52:28 -0700527 // Start reading indications
528 go dh.readIndications()
529 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530530}
531
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400532func (dh *DeviceHandler) populateDeviceInfo() (*oop.DeviceInfo, error) {
533 var err error
534 var deviceInfo *oop.DeviceInfo
535
536 deviceInfo, err = dh.Client.GetDeviceInfo(context.Background(), new(oop.Empty))
537
538 if err != nil {
539 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
540 return nil, err
541 }
542 if deviceInfo == nil {
543 log.Errorw("Device info is nil", log.Fields{})
544 return nil, errors.New("failed to get device info from OLT")
545 }
546
547 log.Debugw("Fetched device info", log.Fields{"deviceInfo": deviceInfo})
548 dh.device.Root = true
549 dh.device.Vendor = deviceInfo.Vendor
550 dh.device.Model = deviceInfo.Model
551 dh.device.SerialNumber = deviceInfo.DeviceSerialNumber
552 dh.device.HardwareVersion = deviceInfo.HardwareVersion
553 dh.device.FirmwareVersion = deviceInfo.FirmwareVersion
554
555 if deviceInfo.DeviceId == "" {
556 log.Warnw("no-device-id-provided-using-host", log.Fields{"hostport": dh.device.GetHostAndPort()})
557 host := strings.Split(dh.device.GetHostAndPort(), ":")[0]
558 genmac, err := generateMacFromHost(host)
559 if err != nil {
560 return nil, err
561 }
562 log.Debugw("using-host-for-mac-address", log.Fields{"host": host, "mac": genmac})
563 dh.device.MacAddress = genmac
564 } else {
565 dh.device.MacAddress = deviceInfo.DeviceId
566 }
567
568 // Synchronous call to update device - this method is run in its own go routine
569 if err := dh.coreProxy.DeviceUpdate(context.TODO(), dh.device); err != nil {
570 log.Errorw("error-updating-device", log.Fields{"deviceID": dh.device.Id, "error": err})
571 return nil, err
572 }
573
574 return deviceInfo, nil
575}
576
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700577//AdoptDevice adopts the OLT device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530578func (dh *DeviceHandler) AdoptDevice(device *voltha.Device) {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400579 dh.transitionMap = NewTransitionMap(dh)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700580 log.Infow("Adopt_device", log.Fields{"deviceID": device.Id, "Address": device.GetHostAndPort()})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400581 dh.transitionMap.Handle(DeviceInit)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530582}
583
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700584//GetOfpDeviceInfo Gets the Ofp information of the given device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530585func (dh *DeviceHandler) GetOfpDeviceInfo(device *voltha.Device) (*ic.SwitchCapability, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700586 return &ic.SwitchCapability{
587 Desc: &of.OfpDesc{
Devmalya Paul70dd4972019-06-10 15:19:17 +0530588 MfrDesc: "VOLTHA Project",
cuilin20187b2a8c32019-03-26 19:52:28 -0700589 HwDesc: "open_pon",
590 SwDesc: "open_pon",
591 SerialNum: dh.device.SerialNumber,
592 },
593 SwitchFeatures: &of.OfpSwitchFeatures{
594 NBuffers: 256,
595 NTables: 2,
596 Capabilities: uint32(of.OfpCapabilities_OFPC_FLOW_STATS |
597 of.OfpCapabilities_OFPC_TABLE_STATS |
598 of.OfpCapabilities_OFPC_PORT_STATS |
599 of.OfpCapabilities_OFPC_GROUP_STATS),
600 },
601 }, nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530602}
603
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700604//GetOfpPortInfo Get Ofp port information
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530605func (dh *DeviceHandler) GetOfpPortInfo(device *voltha.Device, portNo int64) (*ic.PortCapability, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700606 capacity := uint32(of.OfpPortFeatures_OFPPF_1GB_FD | of.OfpPortFeatures_OFPPF_FIBER)
cuilin20187b2a8c32019-03-26 19:52:28 -0700607 return &ic.PortCapability{
608 Port: &voltha.LogicalPort{
609 OfpPort: &of.OfpPort{
610 HwAddr: macAddressToUint32Array(dh.device.MacAddress),
611 Config: 0,
612 State: uint32(of.OfpPortState_OFPPS_LIVE),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700613 Curr: capacity,
614 Advertised: capacity,
615 Peer: capacity,
cuilin20187b2a8c32019-03-26 19:52:28 -0700616 CurrSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
617 MaxSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
618 },
619 DeviceId: dh.device.Id,
620 DevicePortNo: uint32(portNo),
621 },
622 }, nil
623}
624
William Kurkianff524662019-08-20 10:34:30 -0400625func (dh *DeviceHandler) omciIndication(omciInd *oop.OmciIndication) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700626 log.Debugw("omci indication", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700627 var deviceType string
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700628 var deviceID string
629 var proxyDeviceID string
cuilin20187b2a8c32019-03-26 19:52:28 -0700630
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700631 onuKey := dh.formOnuKey(omciInd.IntfId, omciInd.OnuId)
632 if onuInCache, ok := dh.onus[onuKey]; !ok {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700633 log.Debugw("omci indication for a device not in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
634 ponPort := IntfIDToPortNo(omciInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700635 kwargs := make(map[string]interface{})
636 kwargs["onu_id"] = omciInd.OnuId
637 kwargs["parent_port_no"] = ponPort
cuilin20187b2a8c32019-03-26 19:52:28 -0700638
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700639 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
640 if err != nil {
William Kurkianff524662019-08-20 10:34:30 -0400641 log.Errorw("onu not found", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId, "error": err})
642 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700643 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700644 deviceType = onuDevice.Type
645 deviceID = onuDevice.Id
646 proxyDeviceID = onuDevice.ProxyAddress.DeviceId
647 //if not exist in cache, then add to cache.
648 dh.onus[onuKey] = NewOnuDevice(deviceID, deviceType, onuDevice.SerialNumber, omciInd.OnuId, omciInd.IntfId, proxyDeviceID)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700649 } else {
650 //found in cache
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700651 log.Debugw("omci indication for a device in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700652 deviceType = onuInCache.deviceType
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700653 deviceID = onuInCache.deviceID
654 proxyDeviceID = onuInCache.proxyDeviceID
cuilin20187b2a8c32019-03-26 19:52:28 -0700655 }
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700656
657 omciMsg := &ic.InterAdapterOmciMessage{Message: omciInd.Pkt}
658 if sendErr := dh.AdapterProxy.SendInterAdapterMessage(context.Background(), omciMsg,
659 ic.InterAdapterMessageType_OMCI_REQUEST, dh.deviceType, deviceType,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700660 deviceID, proxyDeviceID, ""); sendErr != nil {
William Kurkianff524662019-08-20 10:34:30 -0400661 log.Errorw("send omci request error", log.Fields{"fromAdapter": dh.deviceType, "toAdapter": deviceType, "onuID": deviceID, "proxyDeviceID": proxyDeviceID, "error": sendErr})
662 return
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700663 }
William Kurkianff524662019-08-20 10:34:30 -0400664 return
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530665}
666
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700667//ProcessInterAdapterMessage sends the proxied messages to the target device
668// If the proxy address is not found in the unmarshalled message, it first fetches the onu device for which the message
669// is meant, and then send the unmarshalled omci message to this onu
670func (dh *DeviceHandler) ProcessInterAdapterMessage(msg *ic.InterAdapterMessage) error {
671 log.Debugw("Process_inter_adapter_message", log.Fields{"msgID": msg.Header.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700672 if msg.Header.Type == ic.InterAdapterMessageType_OMCI_REQUEST {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700673 msgID := msg.Header.Id
cuilin20187b2a8c32019-03-26 19:52:28 -0700674 fromTopic := msg.Header.FromTopic
675 toTopic := msg.Header.ToTopic
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700676 toDeviceID := msg.Header.ToDeviceId
677 proxyDeviceID := msg.Header.ProxyDeviceId
cuilin20187b2a8c32019-03-26 19:52:28 -0700678
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700679 log.Debugw("omci request message header", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700680
681 msgBody := msg.GetBody()
682
683 omciMsg := &ic.InterAdapterOmciMessage{}
684 if err := ptypes.UnmarshalAny(msgBody, omciMsg); err != nil {
685 log.Warnw("cannot-unmarshal-omci-msg-body", log.Fields{"error": err})
686 return err
687 }
688
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700689 if omciMsg.GetProxyAddress() == nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700690 onuDevice, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, toDeviceID)
691 if err != nil {
692 log.Errorw("onu not found", log.Fields{"onuDeviceId": toDeviceID, "error": err})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700693 return err
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700694 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700695 log.Debugw("device retrieved from core", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
696 dh.sendProxiedMessage(onuDevice, omciMsg)
697
cuilin20187b2a8c32019-03-26 19:52:28 -0700698 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700699 log.Debugw("Proxy Address found in omci message", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700700 dh.sendProxiedMessage(nil, omciMsg)
cuilin20187b2a8c32019-03-26 19:52:28 -0700701 }
702
703 } else {
704 log.Errorw("inter-adapter-unhandled-type", log.Fields{"msgType": msg.Header.Type})
705 }
706 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530707}
708
cuilin20187b2a8c32019-03-26 19:52:28 -0700709func (dh *DeviceHandler) sendProxiedMessage(onuDevice *voltha.Device, omciMsg *ic.InterAdapterOmciMessage) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700710 var intfID uint32
711 var onuID uint32
712 var connectStatus common.ConnectStatus_ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700713 if onuDevice != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700714 intfID = onuDevice.ProxyAddress.GetChannelId()
715 onuID = onuDevice.ProxyAddress.GetOnuId()
716 connectStatus = onuDevice.ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700717 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700718 intfID = omciMsg.GetProxyAddress().GetChannelId()
719 onuID = omciMsg.GetProxyAddress().GetOnuId()
720 connectStatus = omciMsg.GetConnectStatus()
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700721 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700722 if connectStatus != voltha.ConnectStatus_REACHABLE {
723 log.Debugw("ONU is not reachable, cannot send OMCI", log.Fields{"intfID": intfID, "onuID": onuID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700724 return
725 }
726
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700727 omciMessage := &oop.OmciMsg{IntfId: intfID, OnuId: onuID, Pkt: omciMsg.Message}
cuilin20187b2a8c32019-03-26 19:52:28 -0700728
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700729 _, err := dh.Client.OmciMsgOut(context.Background(), omciMessage)
730 if err != nil {
731 log.Errorw("unable to send omci-msg-out", log.Fields{"IntfID": intfID, "OnuID": onuID, "Msg": omciMessage})
732 return
733 }
734 log.Debugw("omci-message-sent", log.Fields{"intfID": intfID, "onuID": onuID, "omciMsg": string(omciMsg.GetMessage())})
cuilin20187b2a8c32019-03-26 19:52:28 -0700735}
736
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700737func (dh *DeviceHandler) activateONU(intfID uint32, onuID int64, serialNum *oop.SerialNumber, serialNumber string) {
738 log.Debugw("activate-onu", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum, "serialNumber": serialNumber})
739 dh.flowMgr.UpdateOnuInfo(intfID, uint32(onuID), serialNumber)
cuilin20187b2a8c32019-03-26 19:52:28 -0700740 // TODO: need resource manager
741 var pir uint32 = 1000000
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700742 Onu := oop.Onu{IntfId: intfID, OnuId: uint32(onuID), SerialNumber: serialNum, Pir: pir}
manikkaraj kbf256be2019-03-25 00:13:48 +0530743 if _, err := dh.Client.ActivateOnu(context.Background(), &Onu); err != nil {
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400744 st, _ := status.FromError(err)
745 if st.Code() == codes.AlreadyExists {
746 log.Debug("ONU activation is in progress", log.Fields{"SerialNumber": serialNumber})
747 } else {
748 log.Errorw("activate-onu-failed", log.Fields{"Onu": Onu, "err ": err})
749 }
cuilin20187b2a8c32019-03-26 19:52:28 -0700750 } else {
751 log.Infow("activated-onu", log.Fields{"SerialNumber": serialNumber})
752 }
753}
754
Matt Jeanneret53539512019-07-20 14:47:02 -0400755func (dh *DeviceHandler) onuDiscIndication(onuDiscInd *oop.OnuDiscIndication, sn string) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700756 channelID := onuDiscInd.GetIntfId()
757 parentPortNo := IntfIDToPortNo(onuDiscInd.GetIntfId(), voltha.Port_PON_OLT)
Matt Jeanneret53539512019-07-20 14:47:02 -0400758
759 log.Debugw("new-discovery-indication", log.Fields{"sn": sn})
760 dh.lockDevice.Lock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400761 if _, ok := dh.discOnus[sn]; ok {
Matt Jeanneret53539512019-07-20 14:47:02 -0400762 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400763 log.Debugw("onu-sn-is-already-being-processed", log.Fields{"sn": sn})
Matt Jeanneret53539512019-07-20 14:47:02 -0400764 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700765 }
766
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400767 dh.discOnus[sn] = true
Matt Jeanneret53539512019-07-20 14:47:02 -0400768 log.Debugw("new-discovery-indications-list", log.Fields{"discOnus": dh.discOnus})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400769 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400770
cuilin20187b2a8c32019-03-26 19:52:28 -0700771 kwargs := make(map[string]interface{})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400772 if sn != "" {
773 kwargs["serial_number"] = sn
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400774 } else {
Matt Jeanneret53539512019-07-20 14:47:02 -0400775 log.Errorw("invalid onu serial number", log.Fields{"sn": sn})
776 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400777 }
778
779 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
780 var onuID uint32
781 if onuDevice == nil || err != nil {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700782 //This is the first time ONU discovered. Create an OnuID for it.
Matt Jeanneret53539512019-07-20 14:47:02 -0400783 ponintfid := onuDiscInd.GetIntfId()
784 dh.lockDevice.Lock()
785 onuID, err = dh.resourceMgr.GetONUID(ponintfid)
786 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400787 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400788 log.Errorw("failed to fetch onuID from resource manager", log.Fields{"pon-intf-id": ponintfid, "err": err})
789 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400790 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700791 if onuDevice, err = dh.coreProxy.ChildDeviceDetected(context.TODO(), dh.device.Id, int(parentPortNo),
Chaitrashree G See824a22019-07-28 18:28:27 -0400792 "", int(channelID),
Mahir Gunyele77977b2019-06-27 05:36:22 -0700793 string(onuDiscInd.SerialNumber.GetVendorId()), sn, int64(onuID)); onuDevice == nil {
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400794 log.Errorw("Create onu error",
795 log.Fields{"parent_id": dh.device.Id, "ponPort": onuDiscInd.GetIntfId(),
796 "onuID": onuID, "sn": sn, "error": err})
Matt Jeanneret53539512019-07-20 14:47:02 -0400797 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400798 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400799 log.Debugw("onu-child-device-added", log.Fields{"onuDevice": onuDevice})
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400800
801 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700802 //ONU already discovered before. Use the same OnuID.
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400803 onuID = onuDevice.ProxyAddress.OnuId
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400804 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700805 //Insert the ONU into cache to use in OnuIndication.
806 //TODO: Do we need to remove this from the cache on ONU change, or wait for overwritten on next discovery.
Scott Baker7eb0a932019-07-26 10:33:22 -0700807 log.Debugw("ONU discovery indication key create", log.Fields{"onuID": onuID,
808 "intfId": onuDiscInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700809 onuKey := dh.formOnuKey(onuDiscInd.GetIntfId(), onuID)
Matt Jeanneret53539512019-07-20 14:47:02 -0400810
811 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700812 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuID, onuDiscInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400813 log.Debugw("new-onu-device-discovered", log.Fields{"onu": dh.onus[onuKey]})
814 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400815
Mahir Gunyele77977b2019-06-27 05:36:22 -0700816 err = dh.coreProxy.DeviceStateUpdate(context.TODO(), onuDevice.Id, common.ConnectStatus_REACHABLE, common.OperStatus_DISCOVERED)
817 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400818 log.Errorw("failed to update device state", log.Fields{"DeviceID": onuDevice.Id, "err": err})
819 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700820 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700821 log.Debugw("onu-discovered-reachable", log.Fields{"deviceId": onuDevice.Id})
822 //TODO: We put this sleep here to prevent the race between state update and onuIndication
823 //In onuIndication the operStatus of device is checked. If it is still not updated in KV store
824 //then the initialisation fails.
825 time.Sleep(1 * time.Second)
826 dh.activateONU(onuDiscInd.IntfId, int64(onuID), onuDiscInd.SerialNumber, sn)
Matt Jeanneret53539512019-07-20 14:47:02 -0400827 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700828}
829
830func (dh *DeviceHandler) onuIndication(onuInd *oop.OnuIndication) {
831 serialNumber := dh.stringifySerialNumber(onuInd.SerialNumber)
832
833 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700834 ponPort := IntfIDToPortNo(onuInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyele77977b2019-06-27 05:36:22 -0700835 var onuDevice *voltha.Device
836 foundInCache := false
Scott Baker7eb0a932019-07-26 10:33:22 -0700837 log.Debugw("ONU indication key create", log.Fields{"onuId": onuInd.OnuId,
838 "intfId": onuInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700839 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.OnuId)
840 if onuInCache, ok := dh.onus[onuKey]; ok {
841 //If ONU id is discovered before then use GetDevice to get onuDevice because it is cheaper.
842 foundInCache = true
843 onuDevice, _ = dh.coreProxy.GetDevice(nil, dh.device.Id, onuInCache.deviceID)
cuilin20187b2a8c32019-03-26 19:52:28 -0700844 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700845 //If ONU not found in adapter cache then we have to use GetChildDevice to get onuDevice
846 if serialNumber != "" {
847 kwargs["serial_number"] = serialNumber
848 } else {
849 kwargs["onu_id"] = onuInd.OnuId
850 kwargs["parent_port_no"] = ponPort
851 }
852 onuDevice, _ = dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
cuilin20187b2a8c32019-03-26 19:52:28 -0700853 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700854
855 if onuDevice != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400856 if onuDevice.ParentPortNo != ponPort {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700857 //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 -0400858 log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": onuDevice.ParentPortNo, "currentIntfId": ponPort})
cuilin20187b2a8c32019-03-26 19:52:28 -0700859 }
860
861 if onuDevice.ProxyAddress.OnuId != onuInd.OnuId {
862 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})
863 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700864 if !foundInCache {
865 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.GetOnuId())
Matt Jeanneret53539512019-07-20 14:47:02 -0400866 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700867 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuInd.GetOnuId(), onuInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400868 dh.lockDevice.Unlock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700869 }
Scott Baker7eb0a932019-07-26 10:33:22 -0700870 dh.updateOnuStates(onuDevice, onuInd, foundInCache)
cuilin20187b2a8c32019-03-26 19:52:28 -0700871
cuilin20187b2a8c32019-03-26 19:52:28 -0700872 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700873 log.Errorw("onu not found", log.Fields{"intfID": onuInd.IntfId, "onuID": onuInd.OnuId})
cuilin20187b2a8c32019-03-26 19:52:28 -0700874 return
875 }
876
877}
878
Scott Baker7eb0a932019-07-26 10:33:22 -0700879func (dh *DeviceHandler) updateOnuStates(onuDevice *voltha.Device, onuInd *oop.OnuIndication, foundInCache bool) {
Matt Jeanneret53539512019-07-20 14:47:02 -0400880 log.Debugw("onu-indication-for-state", log.Fields{"onuIndication": onuInd, "DeviceId": onuDevice.Id, "operStatus": onuDevice.OperStatus, "adminStatus": onuDevice.AdminState})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700881 dh.updateOnuAdminState(onuInd)
882 // operState
883 if onuInd.OperState == "down" {
Matt Jeanneret53539512019-07-20 14:47:02 -0400884 log.Debugw("sending-interadapter-onu-indication", log.Fields{"onuIndication": onuInd, "DeviceId": onuDevice.Id, "operStatus": onuDevice.OperStatus, "adminStatus": onuDevice.AdminState})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700885 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
886 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
887 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
888 if err != nil {
889 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
890 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
891 }
892 } else if onuInd.OperState == "up" {
Scott Baker7eb0a932019-07-26 10:33:22 -0700893 // Ignore operstatus if device was found in cache
894 if !foundInCache && onuDevice.OperStatus != common.OperStatus_DISCOVERED {
Matt Jeanneret53539512019-07-20 14:47:02 -0400895 log.Warnw("ignore-onu-indication", log.Fields{"intfID": onuInd.IntfId, "onuID": onuInd.OnuId, "operStatus": onuDevice.OperStatus, "msgOperStatus": onuInd.OperState})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700896 return
897 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400898 log.Debugw("sending-interadapter-onu-indication", log.Fields{"onuIndication": onuInd, "DeviceId": onuDevice.Id, "operStatus": onuDevice.OperStatus, "adminStatus": onuDevice.AdminState})
899 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700900 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
901 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
902 if err != nil {
903 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
William Kurkian740a09c2019-10-23 17:07:38 -0400904 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id, "Error": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700905 return
906 }
907 } else {
908 log.Warnw("Not-implemented-or-invalid-value-of-oper-state", log.Fields{"operState": onuInd.OperState})
909 }
910}
911
912func (dh *DeviceHandler) updateOnuAdminState(onuInd *oop.OnuIndication) {
913 if onuInd.AdminState == "down" {
914 if onuInd.OperState != "down" {
915 log.Errorw("ONU-admin-state-down-and-oper-status-not-down", log.Fields{"operState": onuInd.OperState})
916 // Forcing the oper state change code to execute
917 onuInd.OperState = "down"
918 }
919 // Port and logical port update is taken care of by oper state block
920 } else if onuInd.AdminState == "up" {
921 log.Debugln("received-onu-admin-state up")
922 } else {
923 log.Errorw("Invalid-or-not-implemented-admin-state", log.Fields{"received-admin-state": onuInd.AdminState})
924 }
925 log.Debugln("admin-state-dealt-with")
926}
927
cuilin20187b2a8c32019-03-26 19:52:28 -0700928func (dh *DeviceHandler) stringifySerialNumber(serialNum *oop.SerialNumber) string {
929 if serialNum != nil {
930 return string(serialNum.VendorId) + dh.stringifyVendorSpecific(serialNum.VendorSpecific)
cuilin20187b2a8c32019-03-26 19:52:28 -0700931 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700932 return ""
cuilin20187b2a8c32019-03-26 19:52:28 -0700933}
934
935func (dh *DeviceHandler) stringifyVendorSpecific(vendorSpecific []byte) string {
936 tmp := fmt.Sprintf("%x", (uint32(vendorSpecific[0])>>4)&0x0f) +
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700937 fmt.Sprintf("%x", uint32(vendorSpecific[0]&0x0f)) +
cuilin20187b2a8c32019-03-26 19:52:28 -0700938 fmt.Sprintf("%x", (uint32(vendorSpecific[1])>>4)&0x0f) +
939 fmt.Sprintf("%x", (uint32(vendorSpecific[1]))&0x0f) +
940 fmt.Sprintf("%x", (uint32(vendorSpecific[2])>>4)&0x0f) +
941 fmt.Sprintf("%x", (uint32(vendorSpecific[2]))&0x0f) +
942 fmt.Sprintf("%x", (uint32(vendorSpecific[3])>>4)&0x0f) +
943 fmt.Sprintf("%x", (uint32(vendorSpecific[3]))&0x0f)
944 return tmp
945}
946
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700947//UpdateFlowsBulk upates the bulk flow
948func (dh *DeviceHandler) UpdateFlowsBulk() error {
949 return errors.New("unimplemented")
cuilin20187b2a8c32019-03-26 19:52:28 -0700950}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700951
952//GetChildDevice returns the child device for given parent port and onu id
953func (dh *DeviceHandler) GetChildDevice(parentPort, onuID uint32) *voltha.Device {
954 log.Debugw("GetChildDevice", log.Fields{"pon port": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400955 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700956 kwargs["onu_id"] = onuID
Girish Gowdru0c588b22019-04-23 23:24:56 -0400957 kwargs["parent_port_no"] = parentPort
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700958 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400959 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700960 log.Errorw("onu not found", log.Fields{"intfID": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400961 return nil
962 }
963 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
964 return onuDevice
manikkaraj kbf256be2019-03-25 00:13:48 +0530965}
966
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700967// SendPacketInToCore sends packet-in to core
968// For this, it calls SendPacketIn of the core-proxy which uses a device specific topic to send the request.
969// The adapter handling the device creates a device specific topic
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400970func (dh *DeviceHandler) SendPacketInToCore(logicalPort uint32, packetPayload []byte) {
971 log.Debugw("SendPacketInToCore", log.Fields{"port": logicalPort, "packetPayload": packetPayload})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700972 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPort, packetPayload); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400973 log.Errorw("Error sending packetin to core", log.Fields{"error": err})
974 return
975 }
976 log.Debug("Sent packet-in to core successfully")
977}
978
A R Karthick1f85b802019-10-11 05:06:05 +0000979// AddUniPortToOnu adds the uni port to the onu device
980func (dh *DeviceHandler) AddUniPortToOnu(intfID, onuID, uniPort uint32) {
981 onuKey := dh.formOnuKey(intfID, onuID)
982 dh.lockDevice.Lock()
983 defer dh.lockDevice.Unlock()
984 if onuDevice, ok := dh.onus[onuKey]; ok {
985 // add it to the uniPort map for the onu device
986 if _, ok = onuDevice.uniPorts[uniPort]; !ok {
987 onuDevice.uniPorts[uniPort] = struct{}{}
988 log.Debugw("adding-uni-port", log.Fields{"port": uniPort, "intfID": intfID, "onuId": onuID})
989 }
990 }
991}
992
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700993//UpdateFlowsIncrementally updates the device flow
Manikkaraj kb1d51442019-07-23 10:41:02 -0400994func (dh *DeviceHandler) UpdateFlowsIncrementally(device *voltha.Device, flows *of.FlowChanges, groups *of.FlowGroupChanges, flowMetadata *voltha.FlowMetadata) error {
995 log.Debugw("Received-incremental-flowupdate-in-device-handler", log.Fields{"deviceID": device.Id, "flows": flows, "groups": groups, "flowMetadata": flowMetadata})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400996 if flows != nil {
997 for _, flow := range flows.ToAdd.Items {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400998 log.Debug("Adding flow", log.Fields{"deviceId": device.Id, "flowToAdd": flow})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400999 dh.flowMgr.AddFlow(flow, flowMetadata)
Girish Gowdru0c588b22019-04-23 23:24:56 -04001000 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001001 for _, flow := range flows.ToRemove.Items {
1002 log.Debug("Removing flow", log.Fields{"deviceId": device.Id, "flowToRemove": flow})
1003 dh.flowMgr.RemoveFlow(flow)
1004 }
Girish Gowdru0c588b22019-04-23 23:24:56 -04001005 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001006 if groups != nil && flows != nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -04001007 for _, flow := range flows.ToRemove.Items {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001008 log.Debug("Removing flow", log.Fields{"deviceID": device.Id, "flowToRemove": flow})
Girish Gowdru0c588b22019-04-23 23:24:56 -04001009 // dh.flowMgr.RemoveFlow(flow)
1010 }
1011 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001012 log.Debug("UpdateFlowsIncrementally done successfully")
Girish Gowdru0c588b22019-04-23 23:24:56 -04001013 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301014}
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001015
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001016//DisableDevice disables the given device
1017//It marks the following for the given device:
1018//Device-Handler Admin-State : down
1019//Device Port-State: UNKNOWN
1020//Device Oper-State: UNKNOWN
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001021func (dh *DeviceHandler) DisableDevice(device *voltha.Device) error {
Chaitrashree G S44124192019-08-07 20:21:36 -04001022 /* On device disable ,admin state update has to be done prior sending request to agent since
1023 the indication thread may processes invalid indications of ONU and OLT*/
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001024 dh.lockDevice.Lock()
1025 dh.adminState = "down"
1026 dh.lockDevice.Unlock()
Chaitrashree G S44124192019-08-07 20:21:36 -04001027 if _, err := dh.Client.DisableOlt(context.Background(), new(oop.Empty)); err != nil {
1028 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
1029 dh.lockDevice.Lock()
1030 dh.adminState = "up"
1031 dh.lockDevice.Unlock()
1032 return err
1033 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001034 log.Debug("olt-disabled")
Chaitrashree G S44124192019-08-07 20:21:36 -04001035 dh.lockDevice.Lock()
1036 /* Discovered ONUs entries need to be cleared , since on device disable the child devices goes to
1037 UNREACHABLE state which needs to be configured again*/
1038 dh.discOnus = make(map[string]bool)
1039 dh.lockDevice.Unlock()
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001040
1041 cloned := proto.Clone(device).(*voltha.Device)
1042 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001043 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); err != nil {
1044 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001045 return err
1046 }
1047
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001048 log.Debugw("Disable_device-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001049 return nil
1050}
1051
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001052//ReenableDevice re-enables the olt device after disable
1053//It marks the following for the given device:
1054//Device-Handler Admin-State : up
1055//Device Port-State: ACTIVE
1056//Device Oper-State: ACTIVE
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001057func (dh *DeviceHandler) ReenableDevice(device *voltha.Device) error {
1058 if _, err := dh.Client.ReenableOlt(context.Background(), new(oop.Empty)); err != nil {
1059 log.Errorw("Failed to reenable olt ", log.Fields{"err": err})
1060 return err
1061 }
1062
1063 dh.lockDevice.Lock()
1064 dh.adminState = "up"
1065 dh.lockDevice.Unlock()
1066 log.Debug("olt-reenabled")
1067
1068 cloned := proto.Clone(device).(*voltha.Device)
1069 // Update the all ports state on that device to enable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001070 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
1071 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001072 return err
1073 }
1074
1075 //Update the device oper status as ACTIVE
1076 cloned.OperStatus = voltha.OperStatus_ACTIVE
1077 dh.device = cloned
1078
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001079 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1080 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001081 return err
1082 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001083 log.Debugw("ReEnableDevice-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001084
1085 return nil
1086}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001087
A R Karthick1f85b802019-10-11 05:06:05 +00001088func (dh *DeviceHandler) clearUNIData(onu *OnuDevice) error {
Devmalya Paul495b94a2019-08-27 19:42:00 -04001089 var uniID uint32
1090 var err error
A R Karthick1f85b802019-10-11 05:06:05 +00001091 for port := range onu.uniPorts {
1092 delete(onu.uniPorts, port)
1093 uniID = UniIDFromPortNum(port)
1094 log.Debugw("clearing-resource-data-for-uni-port", log.Fields{"port": port, "uniID": uniID})
1095 /* Delete tech-profile instance from the KV store */
1096 if err = dh.flowMgr.DeleteTechProfileInstance(onu.intfID, onu.onuID, uniID, onu.serialNumber); err != nil {
1097 log.Debugw("Failed-to-remove-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
Devmalya Paul495b94a2019-08-27 19:42:00 -04001098 }
A R Karthick1f85b802019-10-11 05:06:05 +00001099 log.Debugw("Deleted-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
1100 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(onu.intfID, onu.onuID, uniID)
1101 for _, flowID := range flowIDs {
1102 dh.resourceMgr.FreeFlowID(onu.intfID, int32(onu.onuID), int32(uniID), flowID)
1103 }
1104 dh.resourceMgr.FreePONResourcesForONU(onu.intfID, onu.onuID, uniID)
1105 if err = dh.resourceMgr.RemoveTechProfileIDForOnu(onu.intfID, onu.onuID, uniID); err != nil {
1106 log.Debugw("Failed-to-remove-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1107 }
1108 log.Debugw("Removed-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1109 if err = dh.resourceMgr.RemoveMeterIDForOnu("upstream", onu.intfID, onu.onuID, uniID); err != nil {
1110 log.Debugw("Failed-to-remove-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1111 }
1112 log.Debugw("Removed-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1113 if err = dh.resourceMgr.RemoveMeterIDForOnu("downstream", onu.intfID, onu.onuID, uniID); err != nil {
1114 log.Debugw("Failed-to-remove-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
1115 }
1116 log.Debugw("Removed-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
Devmalya Paul495b94a2019-08-27 19:42:00 -04001117 }
1118 return nil
1119}
1120
1121func (dh *DeviceHandler) clearNNIData() error {
1122 nniUniID := -1
1123 nniOnuID := -1
1124 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1125 log.Debugw("Current flow ids for nni", log.Fields{"flow-ids": flowIDs})
1126 for _, flowID := range flowIDs {
1127 dh.resourceMgr.FreeFlowID(uint32(dh.nniIntfID), -1, -1, uint32(flowID))
1128 }
1129 //Free the flow-ids for the NNI port
1130 dh.resourceMgr.FreePONResourcesForONU(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1131 /* Free ONU IDs for each pon port
1132 intfIDToONUIds is a map of intf-id: [onu-ids]*/
1133 intfIDToONUIds := make(map[uint32][]uint32)
1134 for _, onu := range dh.onus {
1135 intfIDToONUIds[onu.intfID] = append(intfIDToONUIds[onu.intfID], onu.onuID)
1136 }
1137 for intfID, onuIds := range intfIDToONUIds {
1138 dh.resourceMgr.FreeonuID(intfID, onuIds)
1139 }
1140 return nil
1141}
1142
1143// DeleteDevice deletes the device instance from openolt handler array. Also clears allocated resource manager resources. Also reboots the OLT hardware!
1144func (dh *DeviceHandler) DeleteDevice(device *voltha.Device) error {
1145 log.Debug("Function entry delete device")
1146 dh.lockDevice.Lock()
A R Karthick1f85b802019-10-11 05:06:05 +00001147 if dh.adminState == "deleted" {
1148 dh.lockDevice.Unlock()
1149 return nil
1150 }
Devmalya Paul495b94a2019-08-27 19:42:00 -04001151 dh.adminState = "deleted"
1152 dh.lockDevice.Unlock()
1153 /* Clear the KV store data associated with the all the UNI ports
1154 This clears up flow data and also resource map data for various
1155 other pon resources like alloc_id and gemport_id
1156 */
1157 for _, onu := range dh.onus {
A R Karthick1f85b802019-10-11 05:06:05 +00001158 if err := dh.clearUNIData(onu); err != nil {
Devmalya Paul495b94a2019-08-27 19:42:00 -04001159 log.Debugw("Failed to clear data for onu", log.Fields{"onu-device": onu})
1160 }
1161 }
1162 /* Clear the flows from KV store associated with NNI port.
1163 There are mostly trap rules from NNI port (like LLDP)
1164 */
1165 if err := dh.clearNNIData(); err != nil {
1166 log.Debugw("Failed to clear data for NNI port", log.Fields{"device-id": dh.deviceID})
1167 }
A R Karthick1f85b802019-10-11 05:06:05 +00001168
1169 /* Clear the resource pool for each PON port in the background */
1170 go dh.resourceMgr.Delete()
1171
Devmalya Paul495b94a2019-08-27 19:42:00 -04001172 /*Delete ONU map for the device*/
1173 for onu := range dh.onus {
1174 delete(dh.onus, onu)
1175 }
1176 log.Debug("Removed-device-from-Resource-manager-KV-store")
1177 //Reset the state
1178 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1179 log.Errorw("Failed-to-reboot-olt ", log.Fields{"err": err})
1180 return err
1181 }
1182 cloned := proto.Clone(device).(*voltha.Device)
1183 cloned.OperStatus = voltha.OperStatus_UNKNOWN
1184 cloned.ConnectStatus = voltha.ConnectStatus_UNREACHABLE
1185 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1186 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
1187 return err
1188 }
1189 return nil
1190}
1191
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001192//RebootDevice reboots the given device
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001193func (dh *DeviceHandler) RebootDevice(device *voltha.Device) error {
1194 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1195 log.Errorw("Failed to reboot olt ", log.Fields{"err": err})
1196 return err
1197 }
1198
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001199 log.Debugw("rebooted-device-successfully", log.Fields{"deviceID": device.Id})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001200
1201 return nil
1202}
1203
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001204func (dh *DeviceHandler) handlePacketIndication(packetIn *oop.PacketIndication) {
1205 log.Debugw("Received packet-in", log.Fields{"packet-indication": *packetIn})
1206 logicalPortNum, err := dh.flowMgr.GetLogicalPortFromPacketIn(packetIn)
1207 if err != nil {
1208 log.Errorw("Error getting logical port from packet-in", log.Fields{"error": err})
1209 return
1210 }
1211 log.Debugw("sending packet-in to core", log.Fields{"logicalPortNum": logicalPortNum, "packet": *packetIn})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001212 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPortNum, packetIn.Pkt); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001213 log.Errorw("Error sending packet-in to core", log.Fields{"error": err})
1214 return
1215 }
1216 log.Debug("Success sending packet-in to core!")
1217}
1218
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001219// PacketOut sends packet-out from VOLTHA to OLT on the egress port provided
1220func (dh *DeviceHandler) PacketOut(egressPortNo int, packet *of.OfpPacketOut) error {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001221 log.Debugw("incoming-packet-out", log.Fields{"deviceID": dh.deviceID, "egress_port_no": egressPortNo,
1222 "pkt-length": len(packet.Data), "packetData": hex.EncodeToString(packet.Data)})
1223
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001224 egressPortType := IntfIDToPortTypeName(uint32(egressPortNo))
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001225 if egressPortType == voltha.Port_ETHERNET_UNI {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001226 outerEthType := (uint16(packet.Data[12]) << 8) | uint16(packet.Data[13])
1227 innerEthType := (uint16(packet.Data[16]) << 8) | uint16(packet.Data[17])
1228 if outerEthType == 0x88a8 || outerEthType == 0x8100 {
1229 if innerEthType == 0x8100 {
1230 // q-in-q 802.1ad or 802.1q double tagged packet.
1231 // slice out the outer tag.
1232 packet.Data = append(packet.Data[:12], packet.Data[16:]...)
1233 log.Debugw("packet-now-single-tagged", log.Fields{"packetData": hex.EncodeToString(packet.Data)})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001234 }
1235 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001236 intfID := IntfIDFromUniPortNum(uint32(egressPortNo))
1237 onuID := OnuIDFromPortNum(uint32(egressPortNo))
Manikkaraj kb1d51442019-07-23 10:41:02 -04001238 uniID := UniIDFromPortNum(uint32(egressPortNo))
1239
1240 gemPortID, err := dh.flowMgr.GetPacketOutGemPortID(intfID, onuID, uint32(egressPortNo))
1241 if err != nil {
1242 // In this case the openolt agent will receive the gemPortID as 0.
1243 // The agent tries to retrieve the gemPortID in this case.
1244 // This may not always succeed at the agent and packetOut may fail.
1245 log.Error("failed-to-retrieve-gemport-id-for-packet-out")
1246 }
1247
1248 onuPkt := oop.OnuPacket{IntfId: intfID, OnuId: onuID, PortNo: uint32(egressPortNo), GemportId: gemPortID, Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001249
1250 log.Debugw("sending-packet-to-onu", log.Fields{"egress_port_no": egressPortNo, "IntfId": intfID, "onuID": onuID,
Manikkaraj kb1d51442019-07-23 10:41:02 -04001251 "uniID": uniID, "gemPortID": gemPortID, "packet": hex.EncodeToString(packet.Data)})
Matt Jeanneret1359c732019-08-01 21:40:02 -04001252
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001253 if _, err := dh.Client.OnuPacketOut(context.Background(), &onuPkt); err != nil {
1254 log.Errorw("Error while sending packet-out to ONU", log.Fields{"error": err})
1255 return err
1256 }
1257 } else if egressPortType == voltha.Port_ETHERNET_NNI {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001258 uplinkPkt := oop.UplinkPacket{IntfId: IntfIDFromNniPortNum(uint32(egressPortNo)), Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001259
1260 log.Debugw("sending-packet-to-nni", log.Fields{"uplink_pkt": uplinkPkt, "packet": hex.EncodeToString(packet.Data)})
1261
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001262 if _, err := dh.Client.UplinkPacketOut(context.Background(), &uplinkPkt); err != nil {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001263 log.Errorw("Error while sending packet-out to NNI", log.Fields{"error": err})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001264 return err
1265 }
1266 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001267 log.Warnw("Packet-out-to-this-interface-type-not-implemented", log.Fields{"egress_port_no": egressPortNo, "egressPortType": egressPortType})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001268 }
1269 return nil
1270}
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001271
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001272func (dh *DeviceHandler) formOnuKey(intfID, onuID uint32) string {
1273 return "" + strconv.Itoa(int(intfID)) + "." + strconv.Itoa(int(onuID))
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001274}