blob: 52e4afd92ab3e4300088c61bbb154845ebc986bf [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"
36 com "github.com/opencord/voltha-go/adapters/common"
37 "github.com/opencord/voltha-go/common/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
salmansiddiqui598eb8e2019-08-22 03:58:50 +000048// Constants for number of retries and for timeout
Manikkaraj kb1d51442019-07-23 10:41:02 -040049const (
salmansiddiqui598eb8e2019-08-22 03:58:50 +000050 MaxRetry = 10
51 MaxTimeOutInMs = 500
Manikkaraj kb1d51442019-07-23 10:41:02 -040052)
53
Phaneendra Manda4c62c802019-03-06 21:37:49 +053054//DeviceHandler will interact with the OLT device.
55type DeviceHandler struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070056 deviceID string
cuilin20187b2a8c32019-03-26 19:52:28 -070057 deviceType string
Girish Gowdru5ba46c92019-04-25 05:00:05 -040058 adminState string
cuilin20187b2a8c32019-03-26 19:52:28 -070059 device *voltha.Device
60 coreProxy *com.CoreProxy
manikkaraj kbf256be2019-03-25 00:13:48 +053061 AdapterProxy *com.AdapterProxy
Devmalya Paulfb990a52019-07-09 10:01:49 -040062 EventProxy *com.EventProxy
cuilin20187b2a8c32019-03-26 19:52:28 -070063 openOLT *OpenOLT
cuilin20187b2a8c32019-03-26 19:52:28 -070064 exitChannel chan int
65 lockDevice sync.RWMutex
manikkaraj kbf256be2019-03-25 00:13:48 +053066 Client oop.OpenoltClient
cuilin20187b2a8c32019-03-26 19:52:28 -070067 transitionMap *TransitionMap
68 clientCon *grpc.ClientConn
manikkaraj kbf256be2019-03-25 00:13:48 +053069 flowMgr *OpenOltFlowMgr
Devmalya Paulfb990a52019-07-09 10:01:49 -040070 eventMgr *OpenOltEventMgr
manikkaraj kbf256be2019-03-25 00:13:48 +053071 resourceMgr *rsrcMgr.OpenOltResourceMgr
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -040072 discOnus map[string]bool
Mahir Gunyela3f9add2019-06-06 15:13:19 -070073 onus map[string]*OnuDevice
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070074 nniIntfID int
Mahir Gunyela3f9add2019-06-06 15:13:19 -070075}
76
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070077//OnuDevice represents ONU related info
Mahir Gunyela3f9add2019-06-06 15:13:19 -070078type OnuDevice struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070079 deviceID string
Mahir Gunyela3f9add2019-06-06 15:13:19 -070080 deviceType string
81 serialNumber string
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070082 onuID uint32
83 intfID uint32
84 proxyDeviceID string
Mahir Gunyela3f9add2019-06-06 15:13:19 -070085}
86
87//NewOnuDevice creates a new Onu Device
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070088func NewOnuDevice(devID, deviceTp, serialNum string, onuID, intfID uint32, proxyDevID string) *OnuDevice {
Mahir Gunyela3f9add2019-06-06 15:13:19 -070089 var device OnuDevice
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070090 device.deviceID = devID
Mahir Gunyela3f9add2019-06-06 15:13:19 -070091 device.deviceType = deviceTp
92 device.serialNumber = serialNum
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070093 device.onuID = onuID
94 device.intfID = intfID
95 device.proxyDeviceID = proxyDevID
Mahir Gunyela3f9add2019-06-06 15:13:19 -070096 return &device
Phaneendra Manda4c62c802019-03-06 21:37:49 +053097}
98
99//NewDeviceHandler creates a new device handler
Devmalya Paulfb990a52019-07-09 10:01:49 -0400100func NewDeviceHandler(cp *com.CoreProxy, ap *com.AdapterProxy, ep *com.EventProxy, device *voltha.Device, adapter *OpenOLT) *DeviceHandler {
cuilin20187b2a8c32019-03-26 19:52:28 -0700101 var dh DeviceHandler
102 dh.coreProxy = cp
Girish Gowdru0c588b22019-04-23 23:24:56 -0400103 dh.AdapterProxy = ap
Devmalya Paulfb990a52019-07-09 10:01:49 -0400104 dh.EventProxy = ep
cuilin20187b2a8c32019-03-26 19:52:28 -0700105 cloned := (proto.Clone(device)).(*voltha.Device)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700106 dh.deviceID = cloned.Id
cuilin20187b2a8c32019-03-26 19:52:28 -0700107 dh.deviceType = cloned.Type
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400108 dh.adminState = "up"
cuilin20187b2a8c32019-03-26 19:52:28 -0700109 dh.device = cloned
110 dh.openOLT = adapter
111 dh.exitChannel = make(chan int, 1)
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400112 dh.discOnus = make(map[string]bool)
cuilin20187b2a8c32019-03-26 19:52:28 -0700113 dh.lockDevice = sync.RWMutex{}
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700114 dh.onus = make(map[string]*OnuDevice)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700115 // The nniIntfID is initialized to -1 (invalid) and set to right value
Girish Gowdru1110ef22019-06-24 11:17:59 -0400116 // when the first IntfOperInd with status as "up" is received for
117 // any one of the available NNI port on the OLT device.
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700118 dh.nniIntfID = -1
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530119
cuilin20187b2a8c32019-03-26 19:52:28 -0700120 //TODO initialize the support classes.
121 return &dh
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530122}
123
124// start save the device to the data model
125func (dh *DeviceHandler) start(ctx context.Context) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700126 dh.lockDevice.Lock()
127 defer dh.lockDevice.Unlock()
128 log.Debugw("starting-device-agent", log.Fields{"device": dh.device})
129 // Add the initial device to the local model
130 log.Debug("device-agent-started")
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530131}
132
133// stop stops the device dh. Not much to do for now
134func (dh *DeviceHandler) stop(ctx context.Context) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700135 dh.lockDevice.Lock()
136 defer dh.lockDevice.Unlock()
137 log.Debug("stopping-device-agent")
138 dh.exitChannel <- 1
139 log.Debug("device-agent-stopped")
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530140}
141
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400142func macifyIP(ip net.IP) string {
143 if len(ip) > 0 {
144 oct1 := strconv.FormatInt(int64(ip[12]), 16)
145 oct2 := strconv.FormatInt(int64(ip[13]), 16)
146 oct3 := strconv.FormatInt(int64(ip[14]), 16)
147 oct4 := strconv.FormatInt(int64(ip[15]), 16)
148 return fmt.Sprintf("00:00:%02v:%02v:%02v:%02v", oct1, oct2, oct3, oct4)
149 }
150 return ""
151}
152
153func generateMacFromHost(host string) (string, error) {
154 var genmac string
155 var addr net.IP
156 var ips []string
157 var err error
158
159 log.Debugw("generating-mac-from-host", log.Fields{"host": host})
160
161 if addr = net.ParseIP(host); addr == nil {
162 log.Debugw("looking-up-hostname", log.Fields{"host": host})
163
164 if ips, err = net.LookupHost(host); err == nil {
165 log.Debugw("dns-result-ips", log.Fields{"ips": ips})
166 if addr = net.ParseIP(ips[0]); addr == nil {
167 log.Errorw("unable-to-parse-ip", log.Fields{"ip": ips[0]})
168 return "", errors.New("unable-to-parse-ip")
169 }
170 genmac = macifyIP(addr)
171 log.Debugw("using-ip-as-mac", log.Fields{"host": ips[0], "mac": genmac})
172 return genmac, nil
173 }
174 log.Errorw("cannot-resolve-hostname-to-ip", log.Fields{"host": host})
175 return "", err
176 }
177
178 genmac = macifyIP(addr)
179 log.Debugw("using-ip-as-mac", log.Fields{"host": host, "mac": genmac})
180 return genmac, nil
181}
182
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530183func macAddressToUint32Array(mac string) []uint32 {
cuilin20187b2a8c32019-03-26 19:52:28 -0700184 slist := strings.Split(mac, ":")
185 result := make([]uint32, len(slist))
186 var err error
187 var tmp int64
188 for index, val := range slist {
189 if tmp, err = strconv.ParseInt(val, 16, 32); err != nil {
190 return []uint32{1, 2, 3, 4, 5, 6}
191 }
192 result[index] = uint32(tmp)
193 }
194 return result
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530195}
196
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700197//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 +0530198func GetportLabel(portNum uint32, portType voltha.Port_PortType) string {
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530199
Girish Gowdru0c588b22019-04-23 23:24:56 -0400200 if portType == voltha.Port_ETHERNET_NNI {
201 return fmt.Sprintf("nni-%d", portNum)
202 } else if portType == voltha.Port_PON_OLT {
203 return fmt.Sprintf("pon-%d", portNum)
cuilin20187b2a8c32019-03-26 19:52:28 -0700204 } else if portType == voltha.Port_ETHERNET_UNI {
205 log.Errorw("local UNI management not supported", log.Fields{})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400206 return ""
cuilin20187b2a8c32019-03-26 19:52:28 -0700207 }
208 return ""
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530209}
210
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700211func (dh *DeviceHandler) addPort(intfID uint32, portType voltha.Port_PortType, state string) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700212 var operStatus common.OperStatus_OperStatus
213 if state == "up" {
214 operStatus = voltha.OperStatus_ACTIVE
215 } else {
216 operStatus = voltha.OperStatus_DISCOVERED
217 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700218 portNum := IntfIDToPortNo(intfID, portType)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400219 label := GetportLabel(portNum, portType)
220 if len(label) == 0 {
221 log.Errorw("Invalid-port-label", log.Fields{"portNum": portNum, "portType": portType})
222 return
223 }
224 // Now create Port
225 port := &voltha.Port{
cuilin20187b2a8c32019-03-26 19:52:28 -0700226 PortNo: portNum,
227 Label: label,
228 Type: portType,
229 OperStatus: operStatus,
230 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400231 log.Debugw("Sending port update to core", log.Fields{"port": port})
cuilin20187b2a8c32019-03-26 19:52:28 -0700232 // Synchronous call to update device - this method is run in its own go routine
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700233 if err := dh.coreProxy.PortCreated(context.TODO(), dh.device.Id, port); err != nil {
234 log.Errorw("error-creating-nni-port", log.Fields{"deviceID": dh.device.Id, "portType": portType, "error": err})
Girish Gowdru1110ef22019-06-24 11:17:59 -0400235 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700236
Girish Gowdru1110ef22019-06-24 11:17:59 -0400237 // Once we have successfully added the NNI port to the core, if the
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700238 // locally cached nniIntfID is set to invalid (-1), set it to the right value.
239 if portType == voltha.Port_ETHERNET_NNI && dh.nniIntfID == -1 {
240 dh.nniIntfID = int(intfID)
cuilin20187b2a8c32019-03-26 19:52:28 -0700241 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530242}
243
244// readIndications to read the indications from the OLT device
245func (dh *DeviceHandler) readIndications() {
William Kurkian294a78b2019-08-20 10:34:30 -0400246 defer log.Errorw("Indications ended", log.Fields{})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400247 indications, err := dh.Client.EnableIndication(context.Background(), new(oop.Empty))
cuilin20187b2a8c32019-03-26 19:52:28 -0700248 if err != nil {
249 log.Errorw("Failed to read indications", log.Fields{"err": err})
250 return
251 }
252 if indications == nil {
253 log.Errorw("Indications is nil", log.Fields{})
254 return
255 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400256 /* get device state */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700257 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400258 if err != nil || device == nil {
259 /*TODO: needs to handle error scenarios */
260 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700261 return
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400262 }
263 // When the device is in DISABLED and Adapter container restarts, we need to
264 // rebuild the locally maintained admin state.
265 if device.AdminState == voltha.AdminState_DISABLED {
266 dh.lockDevice.Lock()
267 dh.adminState = "down"
268 dh.lockDevice.Unlock()
269 }
270
cuilin20187b2a8c32019-03-26 19:52:28 -0700271 for {
272 indication, err := indications.Recv()
273 if err == io.EOF {
274 break
275 }
276 if err != nil {
277 log.Infow("Failed to read from indications", log.Fields{"err": err})
Devmalya Pauleb2e9552019-08-27 19:42:00 -0400278 if dh.adminState == "deleted" {
279 log.Debug("Device deleted stoping the read indication thread")
280 break
281 }
Girish Gowdrud4245152019-05-10 00:47:31 -0400282 dh.transitionMap.Handle(DeviceDownInd)
283 dh.transitionMap.Handle(DeviceInit)
284 break
cuilin20187b2a8c32019-03-26 19:52:28 -0700285 }
Chaitrashree G S44124192019-08-07 20:21:36 -0400286 dh.lockDevice.RLock()
287 adminState := dh.adminState
288 dh.lockDevice.RUnlock()
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400289 // When OLT is admin down, allow only NNI operation status change indications.
Chaitrashree G S44124192019-08-07 20:21:36 -0400290 if adminState == "down" {
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400291 _, isIntfOperInd := indication.Data.(*oop.Indication_IntfOperInd)
292 if isIntfOperInd {
293 intfOperInd := indication.GetIntfOperInd()
294 if intfOperInd.GetType() == "nni" {
295 log.Infow("olt is admin down, allow nni ind", log.Fields{})
296 }
297 } else {
298 log.Infow("olt is admin down, ignore indication", log.Fields{})
299 continue
300 }
301 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530302
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700303 dh.handleIndication(indication)
manikkaraj kbf256be2019-03-25 00:13:48 +0530304
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700305 }
306}
307
308func (dh *DeviceHandler) handleOltIndication(oltIndication *oop.OltIndication) {
Daniele Rossi051466a2019-07-26 13:39:37 +0000309 raisedTs := time.Now().UnixNano()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700310 if oltIndication.OperState == "up" {
311 dh.transitionMap.Handle(DeviceUpInd)
312 } else if oltIndication.OperState == "down" {
313 dh.transitionMap.Handle(DeviceDownInd)
314 }
Daniele Rossi051466a2019-07-26 13:39:37 +0000315 // Send or clear Alarm
316 dh.eventMgr.oltUpDownIndication(oltIndication, dh.deviceID, raisedTs)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700317}
318
319func (dh *DeviceHandler) handleIndication(indication *oop.Indication) {
Devmalya Paulfb990a52019-07-09 10:01:49 -0400320 raisedTs := time.Now().UnixNano()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700321 switch indication.Data.(type) {
322 case *oop.Indication_OltInd:
323 dh.handleOltIndication(indication.GetOltInd())
324 case *oop.Indication_IntfInd:
325 intfInd := indication.GetIntfInd()
326 go dh.addPort(intfInd.GetIntfId(), voltha.Port_PON_OLT, intfInd.GetOperState())
327 log.Infow("Received interface indication ", log.Fields{"InterfaceInd": intfInd})
328 case *oop.Indication_IntfOperInd:
329 intfOperInd := indication.GetIntfOperInd()
330 if intfOperInd.GetType() == "nni" {
331 go dh.addPort(intfOperInd.GetIntfId(), voltha.Port_ETHERNET_NNI, intfOperInd.GetOperState())
332 } else if intfOperInd.GetType() == "pon" {
333 // TODO: Check what needs to be handled here for When PON PORT down, ONU will be down
334 // Handle pon port update
cuilin20187b2a8c32019-03-26 19:52:28 -0700335 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700336 log.Infow("Received interface oper indication ", log.Fields{"InterfaceOperInd": intfOperInd})
337 case *oop.Indication_OnuDiscInd:
338 onuDiscInd := indication.GetOnuDiscInd()
339 log.Infow("Received Onu discovery indication ", log.Fields{"OnuDiscInd": onuDiscInd})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700340 sn := dh.stringifySerialNumber(onuDiscInd.SerialNumber)
Matt Jeanneret53539512019-07-20 14:47:02 -0400341 go dh.onuDiscIndication(onuDiscInd, sn)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700342 case *oop.Indication_OnuInd:
343 onuInd := indication.GetOnuInd()
344 log.Infow("Received Onu indication ", log.Fields{"OnuInd": onuInd})
345 go dh.onuIndication(onuInd)
346 case *oop.Indication_OmciInd:
347 omciInd := indication.GetOmciInd()
348 log.Infow("Received Omci indication ", log.Fields{"OmciInd": omciInd})
William Kurkian294a78b2019-08-20 10:34:30 -0400349 go dh.omciIndication(omciInd)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700350 case *oop.Indication_PktInd:
351 pktInd := indication.GetPktInd()
352 log.Infow("Received pakcet indication ", log.Fields{"PktInd": pktInd})
353 go dh.handlePacketIndication(pktInd)
354 case *oop.Indication_PortStats:
355 portStats := indication.GetPortStats()
356 log.Infow("Received port stats indication", log.Fields{"PortStats": portStats})
357 case *oop.Indication_FlowStats:
358 flowStats := indication.GetFlowStats()
359 log.Infow("Received flow stats", log.Fields{"FlowStats": flowStats})
360 case *oop.Indication_AlarmInd:
361 alarmInd := indication.GetAlarmInd()
362 log.Infow("Received alarm indication ", log.Fields{"AlarmInd": alarmInd})
Devmalya Paulfb990a52019-07-09 10:01:49 -0400363 dh.eventMgr.ProcessEvents(alarmInd, dh.deviceID, raisedTs)
364
cuilin20187b2a8c32019-03-26 19:52:28 -0700365 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530366}
367
368// doStateUp handle the olt up indication and update to voltha core
369func (dh *DeviceHandler) doStateUp() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400370 // Synchronous call to update device state - this method is run in its own go routine
cuilin20187b2a8c32019-03-26 19:52:28 -0700371 if err := dh.coreProxy.DeviceStateUpdate(context.Background(), dh.device.Id, voltha.ConnectStatus_REACHABLE,
Girish Gowdru0c588b22019-04-23 23:24:56 -0400372 voltha.OperStatus_ACTIVE); err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700373 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 -0400374 return err
375 }
376 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530377}
378
379// doStateDown handle the olt down indication
380func (dh *DeviceHandler) doStateDown() error {
Girish Gowdrud4245152019-05-10 00:47:31 -0400381 log.Debug("do-state-down-start")
382
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700383 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400384 if err != nil || device == nil {
385 /*TODO: needs to handle error scenarios */
386 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700387 return errors.New("failed to fetch device device")
Girish Gowdrud4245152019-05-10 00:47:31 -0400388 }
389
390 cloned := proto.Clone(device).(*voltha.Device)
391 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700392 if er := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); er != nil {
393 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": er})
394 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400395 }
396
397 //Update the device oper state and connection status
398 cloned.OperStatus = voltha.OperStatus_UNKNOWN
399 cloned.ConnectStatus = common.ConnectStatus_UNREACHABLE
400 dh.device = cloned
401
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700402 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
403 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": er})
404 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400405 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400406
407 //get the child device for the parent device
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700408 onuDevices, err := dh.coreProxy.GetChildDevices(context.TODO(), dh.device.Id)
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400409 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700410 log.Errorw("failed to get child devices information", log.Fields{"deviceID": dh.device.Id, "error": err})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400411 return err
412 }
413 for _, onuDevice := range onuDevices.Items {
414
415 // Update onu state as down in onu adapter
416 onuInd := oop.OnuIndication{}
417 onuInd.OperState = "down"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700418 er := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), &onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
419 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
420 if er != nil {
421 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
422 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
423 return er
424 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400425 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700426 log.Debugw("do-state-down-end", log.Fields{"deviceID": device.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700427 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530428}
429
430// doStateInit dial the grpc before going to init state
431func (dh *DeviceHandler) doStateInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400432 var err error
Girish Gowdrud4245152019-05-10 00:47:31 -0400433 dh.clientCon, err = grpc.Dial(dh.device.GetHostAndPort(), grpc.WithInsecure(), grpc.WithBlock())
Girish Gowdru0c588b22019-04-23 23:24:56 -0400434 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700435 log.Errorw("Failed to dial device", log.Fields{"DeviceId": dh.deviceID, "HostAndPort": dh.device.GetHostAndPort(), "err": err})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400436 return err
437 }
438 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530439}
440
441// postInit create olt client instance to invoke RPC on the olt device
442func (dh *DeviceHandler) postInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400443 dh.Client = oop.NewOpenoltClient(dh.clientCon)
444 dh.transitionMap.Handle(GrpcConnected)
445 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530446}
447
448// doStateConnected get the device info and update to voltha core
449func (dh *DeviceHandler) doStateConnected() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400450 log.Debug("OLT device has been connected")
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400451
452 // Case where OLT is disabled and then rebooted.
453 if dh.adminState == "down" {
454 log.Debugln("do-state-connected--device-admin-state-down")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700455 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400456 if err != nil || device == nil {
457 /*TODO: needs to handle error scenarios */
458 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
459 }
460
461 cloned := proto.Clone(device).(*voltha.Device)
462 cloned.ConnectStatus = voltha.ConnectStatus_REACHABLE
463 cloned.OperStatus = voltha.OperStatus_UNKNOWN
464 dh.device = cloned
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700465 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
466 log.Errorw("error-updating-device-state", log.Fields{"deviceID": dh.device.Id, "error": er})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400467 }
468
Chaitrashree G S44124192019-08-07 20:21:36 -0400469 // 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 -0400470 _, err = dh.Client.DisableOlt(context.Background(), new(oop.Empty))
471 if err != nil {
472 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
473 }
474
475 // Start reading indications
476 go dh.readIndications()
477 return nil
478 }
479
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400480 deviceInfo, err := dh.populateDeviceInfo()
cuilin20187b2a8c32019-03-26 19:52:28 -0700481 if err != nil {
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400482 log.Errorw("Unable to populate Device Info", log.Fields{"err": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700483 return err
484 }
Girish Gowdrud4245152019-05-10 00:47:31 -0400485
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700486 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400487 if err != nil || device == nil {
488 /*TODO: needs to handle error scenarios */
489 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700490 return err
Girish Gowdrud4245152019-05-10 00:47:31 -0400491 }
492 cloned := proto.Clone(device).(*voltha.Device)
493 // Update the all ports (if available) on that device to ACTIVE.
494 // The ports do not normally exist, unless the device is coming back from a reboot
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700495 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
496 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdrud4245152019-05-10 00:47:31 -0400497 return err
498 }
499
Girish Gowdru0c588b22019-04-23 23:24:56 -0400500 KVStoreHostPort := fmt.Sprintf("%s:%d", dh.openOLT.KVStoreHost, dh.openOLT.KVStorePort)
501 // Instantiate resource manager
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700502 if dh.resourceMgr = rsrcMgr.NewResourceMgr(dh.deviceID, KVStoreHostPort, dh.openOLT.KVStoreType, dh.deviceType, deviceInfo); dh.resourceMgr == nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400503 log.Error("Error while instantiating resource manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700504 return errors.New("instantiating resource manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400505 }
506 // Instantiate flow manager
507 if dh.flowMgr = NewFlowManager(dh, dh.resourceMgr); dh.flowMgr == nil {
508 log.Error("Error while instantiating flow manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700509 return errors.New("instantiating flow manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400510 }
511 /* TODO: Instantiate Alarm , stats , BW managers */
Devmalya Paulfb990a52019-07-09 10:01:49 -0400512 /* Instantiating Event Manager to handle Alarms and KPIs */
513 dh.eventMgr = NewEventMgr(dh.EventProxy)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530514
cuilin20187b2a8c32019-03-26 19:52:28 -0700515 // Start reading indications
516 go dh.readIndications()
517 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530518}
519
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400520func (dh *DeviceHandler) populateDeviceInfo() (*oop.DeviceInfo, error) {
521 var err error
522 var deviceInfo *oop.DeviceInfo
523
524 deviceInfo, err = dh.Client.GetDeviceInfo(context.Background(), new(oop.Empty))
525
526 if err != nil {
527 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
528 return nil, err
529 }
530 if deviceInfo == nil {
531 log.Errorw("Device info is nil", log.Fields{})
532 return nil, errors.New("failed to get device info from OLT")
533 }
534
535 log.Debugw("Fetched device info", log.Fields{"deviceInfo": deviceInfo})
536 dh.device.Root = true
537 dh.device.Vendor = deviceInfo.Vendor
538 dh.device.Model = deviceInfo.Model
539 dh.device.SerialNumber = deviceInfo.DeviceSerialNumber
540 dh.device.HardwareVersion = deviceInfo.HardwareVersion
541 dh.device.FirmwareVersion = deviceInfo.FirmwareVersion
542
543 if deviceInfo.DeviceId == "" {
544 log.Warnw("no-device-id-provided-using-host", log.Fields{"hostport": dh.device.GetHostAndPort()})
545 host := strings.Split(dh.device.GetHostAndPort(), ":")[0]
546 genmac, err := generateMacFromHost(host)
547 if err != nil {
548 return nil, err
549 }
550 log.Debugw("using-host-for-mac-address", log.Fields{"host": host, "mac": genmac})
551 dh.device.MacAddress = genmac
552 } else {
553 dh.device.MacAddress = deviceInfo.DeviceId
554 }
555
556 // Synchronous call to update device - this method is run in its own go routine
557 if err := dh.coreProxy.DeviceUpdate(context.TODO(), dh.device); err != nil {
558 log.Errorw("error-updating-device", log.Fields{"deviceID": dh.device.Id, "error": err})
559 return nil, err
560 }
561
562 return deviceInfo, nil
563}
564
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700565//AdoptDevice adopts the OLT device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530566func (dh *DeviceHandler) AdoptDevice(device *voltha.Device) {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400567 dh.transitionMap = NewTransitionMap(dh)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700568 log.Infow("Adopt_device", log.Fields{"deviceID": device.Id, "Address": device.GetHostAndPort()})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400569 dh.transitionMap.Handle(DeviceInit)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530570}
571
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700572//GetOfpDeviceInfo Gets the Ofp information of the given device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530573func (dh *DeviceHandler) GetOfpDeviceInfo(device *voltha.Device) (*ic.SwitchCapability, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700574 return &ic.SwitchCapability{
575 Desc: &of.OfpDesc{
Devmalya Paul70dd4972019-06-10 15:19:17 +0530576 MfrDesc: "VOLTHA Project",
cuilin20187b2a8c32019-03-26 19:52:28 -0700577 HwDesc: "open_pon",
578 SwDesc: "open_pon",
579 SerialNum: dh.device.SerialNumber,
580 },
581 SwitchFeatures: &of.OfpSwitchFeatures{
582 NBuffers: 256,
583 NTables: 2,
584 Capabilities: uint32(of.OfpCapabilities_OFPC_FLOW_STATS |
585 of.OfpCapabilities_OFPC_TABLE_STATS |
586 of.OfpCapabilities_OFPC_PORT_STATS |
587 of.OfpCapabilities_OFPC_GROUP_STATS),
588 },
589 }, nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530590}
591
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700592//GetOfpPortInfo Get Ofp port information
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530593func (dh *DeviceHandler) GetOfpPortInfo(device *voltha.Device, portNo int64) (*ic.PortCapability, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700594 capacity := uint32(of.OfpPortFeatures_OFPPF_1GB_FD | of.OfpPortFeatures_OFPPF_FIBER)
cuilin20187b2a8c32019-03-26 19:52:28 -0700595 return &ic.PortCapability{
596 Port: &voltha.LogicalPort{
597 OfpPort: &of.OfpPort{
598 HwAddr: macAddressToUint32Array(dh.device.MacAddress),
599 Config: 0,
600 State: uint32(of.OfpPortState_OFPPS_LIVE),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700601 Curr: capacity,
602 Advertised: capacity,
603 Peer: capacity,
cuilin20187b2a8c32019-03-26 19:52:28 -0700604 CurrSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
605 MaxSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
606 },
607 DeviceId: dh.device.Id,
608 DevicePortNo: uint32(portNo),
609 },
610 }, nil
611}
612
William Kurkian294a78b2019-08-20 10:34:30 -0400613func (dh *DeviceHandler) omciIndication(omciInd *oop.OmciIndication) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700614 log.Debugw("omci indication", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700615 var deviceType string
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700616 var deviceID string
617 var proxyDeviceID string
cuilin20187b2a8c32019-03-26 19:52:28 -0700618
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700619 onuKey := dh.formOnuKey(omciInd.IntfId, omciInd.OnuId)
620 if onuInCache, ok := dh.onus[onuKey]; !ok {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700621 log.Debugw("omci indication for a device not in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
622 ponPort := IntfIDToPortNo(omciInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700623 kwargs := make(map[string]interface{})
624 kwargs["onu_id"] = omciInd.OnuId
625 kwargs["parent_port_no"] = ponPort
cuilin20187b2a8c32019-03-26 19:52:28 -0700626
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700627 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
628 if err != nil {
William Kurkian294a78b2019-08-20 10:34:30 -0400629 log.Errorw("onu not found", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId, "error": err})
630 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700631 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700632 deviceType = onuDevice.Type
633 deviceID = onuDevice.Id
634 proxyDeviceID = onuDevice.ProxyAddress.DeviceId
635 //if not exist in cache, then add to cache.
636 dh.onus[onuKey] = NewOnuDevice(deviceID, deviceType, onuDevice.SerialNumber, omciInd.OnuId, omciInd.IntfId, proxyDeviceID)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700637 } else {
638 //found in cache
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700639 log.Debugw("omci indication for a device in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700640 deviceType = onuInCache.deviceType
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700641 deviceID = onuInCache.deviceID
642 proxyDeviceID = onuInCache.proxyDeviceID
cuilin20187b2a8c32019-03-26 19:52:28 -0700643 }
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700644
645 omciMsg := &ic.InterAdapterOmciMessage{Message: omciInd.Pkt}
646 if sendErr := dh.AdapterProxy.SendInterAdapterMessage(context.Background(), omciMsg,
647 ic.InterAdapterMessageType_OMCI_REQUEST, dh.deviceType, deviceType,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700648 deviceID, proxyDeviceID, ""); sendErr != nil {
William Kurkian294a78b2019-08-20 10:34:30 -0400649 log.Errorw("send omci request error", log.Fields{"fromAdapter": dh.deviceType, "toAdapter": deviceType, "onuID": deviceID, "proxyDeviceID": proxyDeviceID, "error": sendErr})
650 return
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700651 }
William Kurkian294a78b2019-08-20 10:34:30 -0400652 return
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530653}
654
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700655//ProcessInterAdapterMessage sends the proxied messages to the target device
656// If the proxy address is not found in the unmarshalled message, it first fetches the onu device for which the message
657// is meant, and then send the unmarshalled omci message to this onu
658func (dh *DeviceHandler) ProcessInterAdapterMessage(msg *ic.InterAdapterMessage) error {
659 log.Debugw("Process_inter_adapter_message", log.Fields{"msgID": msg.Header.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700660 if msg.Header.Type == ic.InterAdapterMessageType_OMCI_REQUEST {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700661 msgID := msg.Header.Id
cuilin20187b2a8c32019-03-26 19:52:28 -0700662 fromTopic := msg.Header.FromTopic
663 toTopic := msg.Header.ToTopic
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700664 toDeviceID := msg.Header.ToDeviceId
665 proxyDeviceID := msg.Header.ProxyDeviceId
cuilin20187b2a8c32019-03-26 19:52:28 -0700666
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700667 log.Debugw("omci request message header", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700668
669 msgBody := msg.GetBody()
670
671 omciMsg := &ic.InterAdapterOmciMessage{}
672 if err := ptypes.UnmarshalAny(msgBody, omciMsg); err != nil {
673 log.Warnw("cannot-unmarshal-omci-msg-body", log.Fields{"error": err})
674 return err
675 }
676
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700677 if omciMsg.GetProxyAddress() == nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700678 onuDevice, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, toDeviceID)
679 if err != nil {
680 log.Errorw("onu not found", log.Fields{"onuDeviceId": toDeviceID, "error": err})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700681 return err
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700682 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700683 log.Debugw("device retrieved from core", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
684 dh.sendProxiedMessage(onuDevice, omciMsg)
685
cuilin20187b2a8c32019-03-26 19:52:28 -0700686 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700687 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 -0700688 dh.sendProxiedMessage(nil, omciMsg)
cuilin20187b2a8c32019-03-26 19:52:28 -0700689 }
690
691 } else {
692 log.Errorw("inter-adapter-unhandled-type", log.Fields{"msgType": msg.Header.Type})
693 }
694 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530695}
696
cuilin20187b2a8c32019-03-26 19:52:28 -0700697func (dh *DeviceHandler) sendProxiedMessage(onuDevice *voltha.Device, omciMsg *ic.InterAdapterOmciMessage) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700698 var intfID uint32
699 var onuID uint32
700 var connectStatus common.ConnectStatus_ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700701 if onuDevice != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700702 intfID = onuDevice.ProxyAddress.GetChannelId()
703 onuID = onuDevice.ProxyAddress.GetOnuId()
704 connectStatus = onuDevice.ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700705 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700706 intfID = omciMsg.GetProxyAddress().GetChannelId()
707 onuID = omciMsg.GetProxyAddress().GetOnuId()
708 connectStatus = omciMsg.GetConnectStatus()
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700709 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700710 if connectStatus != voltha.ConnectStatus_REACHABLE {
711 log.Debugw("ONU is not reachable, cannot send OMCI", log.Fields{"intfID": intfID, "onuID": onuID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700712 return
713 }
714
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700715 omciMessage := &oop.OmciMsg{IntfId: intfID, OnuId: onuID, Pkt: omciMsg.Message}
cuilin20187b2a8c32019-03-26 19:52:28 -0700716
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700717 _, err := dh.Client.OmciMsgOut(context.Background(), omciMessage)
718 if err != nil {
719 log.Errorw("unable to send omci-msg-out", log.Fields{"IntfID": intfID, "OnuID": onuID, "Msg": omciMessage})
720 return
721 }
722 log.Debugw("omci-message-sent", log.Fields{"intfID": intfID, "onuID": onuID, "omciMsg": string(omciMsg.GetMessage())})
cuilin20187b2a8c32019-03-26 19:52:28 -0700723}
724
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700725func (dh *DeviceHandler) activateONU(intfID uint32, onuID int64, serialNum *oop.SerialNumber, serialNumber string) {
726 log.Debugw("activate-onu", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum, "serialNumber": serialNumber})
727 dh.flowMgr.UpdateOnuInfo(intfID, uint32(onuID), serialNumber)
cuilin20187b2a8c32019-03-26 19:52:28 -0700728 // TODO: need resource manager
729 var pir uint32 = 1000000
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700730 Onu := oop.Onu{IntfId: intfID, OnuId: uint32(onuID), SerialNumber: serialNum, Pir: pir}
manikkaraj kbf256be2019-03-25 00:13:48 +0530731 if _, err := dh.Client.ActivateOnu(context.Background(), &Onu); err != nil {
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400732 st, _ := status.FromError(err)
733 if st.Code() == codes.AlreadyExists {
734 log.Debug("ONU activation is in progress", log.Fields{"SerialNumber": serialNumber})
735 } else {
736 log.Errorw("activate-onu-failed", log.Fields{"Onu": Onu, "err ": err})
737 }
cuilin20187b2a8c32019-03-26 19:52:28 -0700738 } else {
739 log.Infow("activated-onu", log.Fields{"SerialNumber": serialNumber})
740 }
741}
742
Matt Jeanneret53539512019-07-20 14:47:02 -0400743func (dh *DeviceHandler) onuDiscIndication(onuDiscInd *oop.OnuDiscIndication, sn string) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700744 channelID := onuDiscInd.GetIntfId()
745 parentPortNo := IntfIDToPortNo(onuDiscInd.GetIntfId(), voltha.Port_PON_OLT)
Matt Jeanneret53539512019-07-20 14:47:02 -0400746
747 log.Debugw("new-discovery-indication", log.Fields{"sn": sn})
748 dh.lockDevice.Lock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400749 if _, ok := dh.discOnus[sn]; ok {
Matt Jeanneret53539512019-07-20 14:47:02 -0400750 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400751 log.Debugw("onu-sn-is-already-being-processed", log.Fields{"sn": sn})
Matt Jeanneret53539512019-07-20 14:47:02 -0400752 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700753 }
754
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400755 dh.discOnus[sn] = true
Matt Jeanneret53539512019-07-20 14:47:02 -0400756 log.Debugw("new-discovery-indications-list", log.Fields{"discOnus": dh.discOnus})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400757 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400758
cuilin20187b2a8c32019-03-26 19:52:28 -0700759 kwargs := make(map[string]interface{})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400760 if sn != "" {
761 kwargs["serial_number"] = sn
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400762 } else {
Matt Jeanneret53539512019-07-20 14:47:02 -0400763 log.Errorw("invalid onu serial number", log.Fields{"sn": sn})
764 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400765 }
766
767 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
768 var onuID uint32
769 if onuDevice == nil || err != nil {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700770 //This is the first time ONU discovered. Create an OnuID for it.
Matt Jeanneret53539512019-07-20 14:47:02 -0400771 ponintfid := onuDiscInd.GetIntfId()
772 dh.lockDevice.Lock()
773 onuID, err = dh.resourceMgr.GetONUID(ponintfid)
774 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400775 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400776 log.Errorw("failed to fetch onuID from resource manager", log.Fields{"pon-intf-id": ponintfid, "err": err})
777 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400778 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700779 if onuDevice, err = dh.coreProxy.ChildDeviceDetected(context.TODO(), dh.device.Id, int(parentPortNo),
Chaitrashree G See824a22019-07-28 18:28:27 -0400780 "", int(channelID),
Mahir Gunyele77977b2019-06-27 05:36:22 -0700781 string(onuDiscInd.SerialNumber.GetVendorId()), sn, int64(onuID)); onuDevice == nil {
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400782 log.Errorw("Create onu error",
783 log.Fields{"parent_id": dh.device.Id, "ponPort": onuDiscInd.GetIntfId(),
784 "onuID": onuID, "sn": sn, "error": err})
Matt Jeanneret53539512019-07-20 14:47:02 -0400785 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400786 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400787 log.Debugw("onu-child-device-added", log.Fields{"onuDevice": onuDevice})
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400788
789 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700790 //ONU already discovered before. Use the same OnuID.
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400791 onuID = onuDevice.ProxyAddress.OnuId
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400792 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700793 //Insert the ONU into cache to use in OnuIndication.
794 //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 -0700795 log.Debugw("ONU discovery indication key create", log.Fields{"onuID": onuID,
796 "intfId": onuDiscInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700797 onuKey := dh.formOnuKey(onuDiscInd.GetIntfId(), onuID)
Matt Jeanneret53539512019-07-20 14:47:02 -0400798
799 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700800 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuID, onuDiscInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400801 log.Debugw("new-onu-device-discovered", log.Fields{"onu": dh.onus[onuKey]})
802 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400803
Mahir Gunyele77977b2019-06-27 05:36:22 -0700804 err = dh.coreProxy.DeviceStateUpdate(context.TODO(), onuDevice.Id, common.ConnectStatus_REACHABLE, common.OperStatus_DISCOVERED)
805 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400806 log.Errorw("failed to update device state", log.Fields{"DeviceID": onuDevice.Id, "err": err})
807 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700808 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700809 log.Debugw("onu-discovered-reachable", log.Fields{"deviceId": onuDevice.Id})
810 //TODO: We put this sleep here to prevent the race between state update and onuIndication
811 //In onuIndication the operStatus of device is checked. If it is still not updated in KV store
812 //then the initialisation fails.
813 time.Sleep(1 * time.Second)
814 dh.activateONU(onuDiscInd.IntfId, int64(onuID), onuDiscInd.SerialNumber, sn)
Matt Jeanneret53539512019-07-20 14:47:02 -0400815 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700816}
817
818func (dh *DeviceHandler) onuIndication(onuInd *oop.OnuIndication) {
819 serialNumber := dh.stringifySerialNumber(onuInd.SerialNumber)
820
821 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700822 ponPort := IntfIDToPortNo(onuInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyele77977b2019-06-27 05:36:22 -0700823 var onuDevice *voltha.Device
824 foundInCache := false
Scott Baker7eb0a932019-07-26 10:33:22 -0700825 log.Debugw("ONU indication key create", log.Fields{"onuId": onuInd.OnuId,
826 "intfId": onuInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700827 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.OnuId)
828 if onuInCache, ok := dh.onus[onuKey]; ok {
829 //If ONU id is discovered before then use GetDevice to get onuDevice because it is cheaper.
830 foundInCache = true
831 onuDevice, _ = dh.coreProxy.GetDevice(nil, dh.device.Id, onuInCache.deviceID)
cuilin20187b2a8c32019-03-26 19:52:28 -0700832 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700833 //If ONU not found in adapter cache then we have to use GetChildDevice to get onuDevice
834 if serialNumber != "" {
835 kwargs["serial_number"] = serialNumber
836 } else {
837 kwargs["onu_id"] = onuInd.OnuId
838 kwargs["parent_port_no"] = ponPort
839 }
840 onuDevice, _ = dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
cuilin20187b2a8c32019-03-26 19:52:28 -0700841 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700842
843 if onuDevice != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400844 if onuDevice.ParentPortNo != ponPort {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700845 //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 -0400846 log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": onuDevice.ParentPortNo, "currentIntfId": ponPort})
cuilin20187b2a8c32019-03-26 19:52:28 -0700847 }
848
849 if onuDevice.ProxyAddress.OnuId != onuInd.OnuId {
850 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})
851 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700852 if !foundInCache {
853 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.GetOnuId())
Matt Jeanneret53539512019-07-20 14:47:02 -0400854 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700855 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuInd.GetOnuId(), onuInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400856 dh.lockDevice.Unlock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700857 }
Scott Baker7eb0a932019-07-26 10:33:22 -0700858 dh.updateOnuStates(onuDevice, onuInd, foundInCache)
cuilin20187b2a8c32019-03-26 19:52:28 -0700859
cuilin20187b2a8c32019-03-26 19:52:28 -0700860 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700861 log.Errorw("onu not found", log.Fields{"intfID": onuInd.IntfId, "onuID": onuInd.OnuId})
cuilin20187b2a8c32019-03-26 19:52:28 -0700862 return
863 }
864
865}
866
Scott Baker7eb0a932019-07-26 10:33:22 -0700867func (dh *DeviceHandler) updateOnuStates(onuDevice *voltha.Device, onuInd *oop.OnuIndication, foundInCache bool) {
Matt Jeanneret53539512019-07-20 14:47:02 -0400868 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 -0700869 dh.updateOnuAdminState(onuInd)
870 // operState
871 if onuInd.OperState == "down" {
Matt Jeanneret53539512019-07-20 14:47:02 -0400872 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 -0700873 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
874 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
875 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
876 if err != nil {
877 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
878 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
879 }
880 } else if onuInd.OperState == "up" {
Scott Baker7eb0a932019-07-26 10:33:22 -0700881 // Ignore operstatus if device was found in cache
882 if !foundInCache && onuDevice.OperStatus != common.OperStatus_DISCOVERED {
Matt Jeanneret53539512019-07-20 14:47:02 -0400883 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 -0700884 return
885 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400886 log.Debugw("sending-interadapter-onu-indication", log.Fields{"onuIndication": onuInd, "DeviceId": onuDevice.Id, "operStatus": onuDevice.OperStatus, "adminStatus": onuDevice.AdminState})
887 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700888 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
889 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
890 if err != nil {
891 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
892 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
893 return
894 }
895 } else {
896 log.Warnw("Not-implemented-or-invalid-value-of-oper-state", log.Fields{"operState": onuInd.OperState})
897 }
898}
899
900func (dh *DeviceHandler) updateOnuAdminState(onuInd *oop.OnuIndication) {
901 if onuInd.AdminState == "down" {
902 if onuInd.OperState != "down" {
903 log.Errorw("ONU-admin-state-down-and-oper-status-not-down", log.Fields{"operState": onuInd.OperState})
904 // Forcing the oper state change code to execute
905 onuInd.OperState = "down"
906 }
907 // Port and logical port update is taken care of by oper state block
908 } else if onuInd.AdminState == "up" {
909 log.Debugln("received-onu-admin-state up")
910 } else {
911 log.Errorw("Invalid-or-not-implemented-admin-state", log.Fields{"received-admin-state": onuInd.AdminState})
912 }
913 log.Debugln("admin-state-dealt-with")
914}
915
cuilin20187b2a8c32019-03-26 19:52:28 -0700916func (dh *DeviceHandler) stringifySerialNumber(serialNum *oop.SerialNumber) string {
917 if serialNum != nil {
918 return string(serialNum.VendorId) + dh.stringifyVendorSpecific(serialNum.VendorSpecific)
cuilin20187b2a8c32019-03-26 19:52:28 -0700919 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700920 return ""
cuilin20187b2a8c32019-03-26 19:52:28 -0700921}
922
923func (dh *DeviceHandler) stringifyVendorSpecific(vendorSpecific []byte) string {
924 tmp := fmt.Sprintf("%x", (uint32(vendorSpecific[0])>>4)&0x0f) +
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700925 fmt.Sprintf("%x", uint32(vendorSpecific[0]&0x0f)) +
cuilin20187b2a8c32019-03-26 19:52:28 -0700926 fmt.Sprintf("%x", (uint32(vendorSpecific[1])>>4)&0x0f) +
927 fmt.Sprintf("%x", (uint32(vendorSpecific[1]))&0x0f) +
928 fmt.Sprintf("%x", (uint32(vendorSpecific[2])>>4)&0x0f) +
929 fmt.Sprintf("%x", (uint32(vendorSpecific[2]))&0x0f) +
930 fmt.Sprintf("%x", (uint32(vendorSpecific[3])>>4)&0x0f) +
931 fmt.Sprintf("%x", (uint32(vendorSpecific[3]))&0x0f)
932 return tmp
933}
934
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700935//UpdateFlowsBulk upates the bulk flow
936func (dh *DeviceHandler) UpdateFlowsBulk() error {
937 return errors.New("unimplemented")
cuilin20187b2a8c32019-03-26 19:52:28 -0700938}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700939
940//GetChildDevice returns the child device for given parent port and onu id
941func (dh *DeviceHandler) GetChildDevice(parentPort, onuID uint32) *voltha.Device {
942 log.Debugw("GetChildDevice", log.Fields{"pon port": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400943 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700944 kwargs["onu_id"] = onuID
Girish Gowdru0c588b22019-04-23 23:24:56 -0400945 kwargs["parent_port_no"] = parentPort
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700946 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400947 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700948 log.Errorw("onu not found", log.Fields{"intfID": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400949 return nil
950 }
951 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
952 return onuDevice
manikkaraj kbf256be2019-03-25 00:13:48 +0530953}
954
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700955// SendPacketInToCore sends packet-in to core
956// For this, it calls SendPacketIn of the core-proxy which uses a device specific topic to send the request.
957// The adapter handling the device creates a device specific topic
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400958func (dh *DeviceHandler) SendPacketInToCore(logicalPort uint32, packetPayload []byte) {
959 log.Debugw("SendPacketInToCore", log.Fields{"port": logicalPort, "packetPayload": packetPayload})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700960 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPort, packetPayload); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400961 log.Errorw("Error sending packetin to core", log.Fields{"error": err})
962 return
963 }
964 log.Debug("Sent packet-in to core successfully")
965}
966
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700967//UpdateFlowsIncrementally updates the device flow
Manikkaraj kb1d51442019-07-23 10:41:02 -0400968func (dh *DeviceHandler) UpdateFlowsIncrementally(device *voltha.Device, flows *of.FlowChanges, groups *of.FlowGroupChanges, flowMetadata *voltha.FlowMetadata) error {
969 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 -0400970 if flows != nil {
971 for _, flow := range flows.ToAdd.Items {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400972 log.Debug("Adding flow", log.Fields{"deviceId": device.Id, "flowToAdd": flow})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400973 dh.flowMgr.AddFlow(flow, flowMetadata)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400974 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400975 for _, flow := range flows.ToRemove.Items {
976 log.Debug("Removing flow", log.Fields{"deviceId": device.Id, "flowToRemove": flow})
977 dh.flowMgr.RemoveFlow(flow)
978 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400979 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700980 if groups != nil && flows != nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400981 for _, flow := range flows.ToRemove.Items {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700982 log.Debug("Removing flow", log.Fields{"deviceID": device.Id, "flowToRemove": flow})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400983 // dh.flowMgr.RemoveFlow(flow)
984 }
985 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400986 log.Debug("UpdateFlowsIncrementally done successfully")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400987 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530988}
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400989
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700990//DisableDevice disables the given device
991//It marks the following for the given device:
992//Device-Handler Admin-State : down
993//Device Port-State: UNKNOWN
994//Device Oper-State: UNKNOWN
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400995func (dh *DeviceHandler) DisableDevice(device *voltha.Device) error {
Chaitrashree G S44124192019-08-07 20:21:36 -0400996 /* On device disable ,admin state update has to be done prior sending request to agent since
997 the indication thread may processes invalid indications of ONU and OLT*/
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400998 dh.lockDevice.Lock()
999 dh.adminState = "down"
1000 dh.lockDevice.Unlock()
Chaitrashree G S44124192019-08-07 20:21:36 -04001001 if _, err := dh.Client.DisableOlt(context.Background(), new(oop.Empty)); err != nil {
1002 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
1003 dh.lockDevice.Lock()
1004 dh.adminState = "up"
1005 dh.lockDevice.Unlock()
1006 return err
1007 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001008 log.Debug("olt-disabled")
Chaitrashree G S44124192019-08-07 20:21:36 -04001009 dh.lockDevice.Lock()
1010 /* Discovered ONUs entries need to be cleared , since on device disable the child devices goes to
1011 UNREACHABLE state which needs to be configured again*/
1012 dh.discOnus = make(map[string]bool)
1013 dh.lockDevice.Unlock()
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001014
1015 cloned := proto.Clone(device).(*voltha.Device)
1016 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001017 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); err != nil {
1018 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001019 return err
1020 }
1021
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001022 log.Debugw("Disable_device-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001023 return nil
1024}
1025
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001026//ReenableDevice re-enables the olt device after disable
1027//It marks the following for the given device:
1028//Device-Handler Admin-State : up
1029//Device Port-State: ACTIVE
1030//Device Oper-State: ACTIVE
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001031func (dh *DeviceHandler) ReenableDevice(device *voltha.Device) error {
1032 if _, err := dh.Client.ReenableOlt(context.Background(), new(oop.Empty)); err != nil {
1033 log.Errorw("Failed to reenable olt ", log.Fields{"err": err})
1034 return err
1035 }
1036
1037 dh.lockDevice.Lock()
1038 dh.adminState = "up"
1039 dh.lockDevice.Unlock()
1040 log.Debug("olt-reenabled")
1041
1042 cloned := proto.Clone(device).(*voltha.Device)
1043 // Update the all ports state on that device to enable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001044 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
1045 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001046 return err
1047 }
1048
1049 //Update the device oper status as ACTIVE
1050 cloned.OperStatus = voltha.OperStatus_ACTIVE
1051 dh.device = cloned
1052
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001053 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1054 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001055 return err
1056 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001057 log.Debugw("ReEnableDevice-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001058
1059 return nil
1060}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001061
Devmalya Pauleb2e9552019-08-27 19:42:00 -04001062func (dh *DeviceHandler) clearUNIData(onu *OnuDevice, uniPorts []*voltha.Port) error {
1063 var uniID uint32
1064 var err error
1065 for _, port := range uniPorts {
1066 if port.Type == voltha.Port_ETHERNET_UNI {
1067 uniID = UniIDFromPortNum(port.PortNo)
1068 /* Delete tech-profile instance from the KV store */
1069 if err = dh.flowMgr.DeleteTechProfileInstance(onu.intfID, onu.onuID, uniID, onu.serialNumber); err != nil {
1070 log.Debugw("Failed-to-remove-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
1071 }
1072 log.Debugw("Deleted-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
1073 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(onu.intfID, onu.onuID, uniID)
1074 for _, flowID := range flowIDs {
1075 dh.resourceMgr.FreeFlowID(onu.intfID, int32(onu.onuID), int32(uniID), flowID)
1076 }
1077 dh.resourceMgr.FreePONResourcesForONU(onu.intfID, onu.onuID, uniID)
1078 if err = dh.resourceMgr.RemoveTechProfileIDForOnu(onu.intfID, onu.onuID, uniID); err != nil {
1079 log.Debugw("Failed-to-remove-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1080 }
1081 log.Debugw("Removed-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1082 if err = dh.resourceMgr.RemoveMeterIDForOnu("upstream", onu.intfID, onu.onuID, uniID); err != nil {
1083 log.Debugw("Failed-to-remove-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1084 }
1085 log.Debugw("Removed-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1086 if err = dh.resourceMgr.RemoveMeterIDForOnu("downstream", onu.intfID, onu.onuID, uniID); err != nil {
1087 log.Debugw("Failed-to-remove-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
1088 }
1089 log.Debugw("Removed-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
1090 }
1091 }
1092 return nil
1093}
1094
1095func (dh *DeviceHandler) clearNNIData() error {
1096 nniUniID := -1
1097 nniOnuID := -1
1098 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1099 log.Debugw("Current flow ids for nni", log.Fields{"flow-ids": flowIDs})
1100 for _, flowID := range flowIDs {
1101 dh.resourceMgr.FreeFlowID(uint32(dh.nniIntfID), -1, -1, uint32(flowID))
1102 }
1103 //Free the flow-ids for the NNI port
1104 dh.resourceMgr.FreePONResourcesForONU(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1105 /* Free ONU IDs for each pon port
1106 intfIDToONUIds is a map of intf-id: [onu-ids]*/
1107 intfIDToONUIds := make(map[uint32][]uint32)
1108 for _, onu := range dh.onus {
1109 intfIDToONUIds[onu.intfID] = append(intfIDToONUIds[onu.intfID], onu.onuID)
1110 }
1111 for intfID, onuIds := range intfIDToONUIds {
1112 dh.resourceMgr.FreeonuID(intfID, onuIds)
1113 }
1114 return nil
1115}
1116
1117// DeleteDevice deletes the device instance from openolt handler array. Also clears allocated resource manager resources. Also reboots the OLT hardware!
1118func (dh *DeviceHandler) DeleteDevice(device *voltha.Device) error {
1119 log.Debug("Function entry delete device")
1120 dh.lockDevice.Lock()
1121 dh.adminState = "deleted"
1122 dh.lockDevice.Unlock()
1123 /* Clear the KV store data associated with the all the UNI ports
1124 This clears up flow data and also resource map data for various
1125 other pon resources like alloc_id and gemport_id
1126 */
1127 for _, onu := range dh.onus {
1128 childDevice, err := dh.coreProxy.GetDevice(nil, dh.deviceID, onu.deviceID)
1129 if err != nil {
1130 log.Debug("Failed to get onu device")
1131 continue
1132 }
1133 uniPorts := childDevice.Ports
1134 log.Debugw("onu-uni-ports", log.Fields{"onu-ports": uniPorts})
1135 if err := dh.clearUNIData(onu, uniPorts); err != nil {
1136 log.Debugw("Failed to clear data for onu", log.Fields{"onu-device": onu})
1137 }
1138 }
1139 /* Clear the flows from KV store associated with NNI port.
1140 There are mostly trap rules from NNI port (like LLDP)
1141 */
1142 if err := dh.clearNNIData(); err != nil {
1143 log.Debugw("Failed to clear data for NNI port", log.Fields{"device-id": dh.deviceID})
1144 }
1145 /* Clear the resource pool for each PON port*/
1146 if err := dh.resourceMgr.Delete(); err != nil {
1147 log.Debug("Failed-to-remove-device-from-Resource-mananger-KV-store")
1148 }
1149 /*Delete ONU map for the device*/
1150 for onu := range dh.onus {
1151 delete(dh.onus, onu)
1152 }
1153 log.Debug("Removed-device-from-Resource-manager-KV-store")
1154 //Reset the state
1155 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1156 log.Errorw("Failed-to-reboot-olt ", log.Fields{"err": err})
1157 return err
1158 }
1159 cloned := proto.Clone(device).(*voltha.Device)
1160 cloned.OperStatus = voltha.OperStatus_UNKNOWN
1161 cloned.ConnectStatus = voltha.ConnectStatus_UNREACHABLE
1162 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1163 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
1164 return err
1165 }
1166 return nil
1167}
1168
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001169//RebootDevice reboots the given device
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001170func (dh *DeviceHandler) RebootDevice(device *voltha.Device) error {
1171 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1172 log.Errorw("Failed to reboot olt ", log.Fields{"err": err})
1173 return err
1174 }
1175
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001176 log.Debugw("rebooted-device-successfully", log.Fields{"deviceID": device.Id})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001177
1178 return nil
1179}
1180
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001181func (dh *DeviceHandler) handlePacketIndication(packetIn *oop.PacketIndication) {
1182 log.Debugw("Received packet-in", log.Fields{"packet-indication": *packetIn})
1183 logicalPortNum, err := dh.flowMgr.GetLogicalPortFromPacketIn(packetIn)
1184 if err != nil {
1185 log.Errorw("Error getting logical port from packet-in", log.Fields{"error": err})
1186 return
1187 }
1188 log.Debugw("sending packet-in to core", log.Fields{"logicalPortNum": logicalPortNum, "packet": *packetIn})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001189 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPortNum, packetIn.Pkt); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001190 log.Errorw("Error sending packet-in to core", log.Fields{"error": err})
1191 return
1192 }
1193 log.Debug("Success sending packet-in to core!")
1194}
1195
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001196// PacketOut sends packet-out from VOLTHA to OLT on the egress port provided
1197func (dh *DeviceHandler) PacketOut(egressPortNo int, packet *of.OfpPacketOut) error {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001198 log.Debugw("incoming-packet-out", log.Fields{"deviceID": dh.deviceID, "egress_port_no": egressPortNo,
1199 "pkt-length": len(packet.Data), "packetData": hex.EncodeToString(packet.Data)})
1200
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001201 egressPortType := IntfIDToPortTypeName(uint32(egressPortNo))
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001202 if egressPortType == voltha.Port_ETHERNET_UNI {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001203 outerEthType := (uint16(packet.Data[12]) << 8) | uint16(packet.Data[13])
1204 innerEthType := (uint16(packet.Data[16]) << 8) | uint16(packet.Data[17])
1205 if outerEthType == 0x88a8 || outerEthType == 0x8100 {
1206 if innerEthType == 0x8100 {
1207 // q-in-q 802.1ad or 802.1q double tagged packet.
1208 // slice out the outer tag.
1209 packet.Data = append(packet.Data[:12], packet.Data[16:]...)
1210 log.Debugw("packet-now-single-tagged", log.Fields{"packetData": hex.EncodeToString(packet.Data)})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001211 }
1212 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001213 intfID := IntfIDFromUniPortNum(uint32(egressPortNo))
1214 onuID := OnuIDFromPortNum(uint32(egressPortNo))
Manikkaraj kb1d51442019-07-23 10:41:02 -04001215 uniID := UniIDFromPortNum(uint32(egressPortNo))
1216
1217 gemPortID, err := dh.flowMgr.GetPacketOutGemPortID(intfID, onuID, uint32(egressPortNo))
1218 if err != nil {
1219 // In this case the openolt agent will receive the gemPortID as 0.
1220 // The agent tries to retrieve the gemPortID in this case.
1221 // This may not always succeed at the agent and packetOut may fail.
1222 log.Error("failed-to-retrieve-gemport-id-for-packet-out")
1223 }
1224
1225 onuPkt := oop.OnuPacket{IntfId: intfID, OnuId: onuID, PortNo: uint32(egressPortNo), GemportId: gemPortID, Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001226
1227 log.Debugw("sending-packet-to-onu", log.Fields{"egress_port_no": egressPortNo, "IntfId": intfID, "onuID": onuID,
Manikkaraj kb1d51442019-07-23 10:41:02 -04001228 "uniID": uniID, "gemPortID": gemPortID, "packet": hex.EncodeToString(packet.Data)})
Matt Jeanneret1359c732019-08-01 21:40:02 -04001229
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001230 if _, err := dh.Client.OnuPacketOut(context.Background(), &onuPkt); err != nil {
1231 log.Errorw("Error while sending packet-out to ONU", log.Fields{"error": err})
1232 return err
1233 }
1234 } else if egressPortType == voltha.Port_ETHERNET_NNI {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001235 uplinkPkt := oop.UplinkPacket{IntfId: IntfIDFromNniPortNum(uint32(egressPortNo)), Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001236
1237 log.Debugw("sending-packet-to-nni", log.Fields{"uplink_pkt": uplinkPkt, "packet": hex.EncodeToString(packet.Data)})
1238
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001239 if _, err := dh.Client.UplinkPacketOut(context.Background(), &uplinkPkt); err != nil {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001240 log.Errorw("Error while sending packet-out to NNI", log.Fields{"error": err})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001241 return err
1242 }
1243 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001244 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 -04001245 }
1246 return nil
1247}
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001248
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001249func (dh *DeviceHandler) formOnuKey(intfID, onuID uint32) string {
1250 return "" + strconv.Itoa(int(intfID)) + "." + strconv.Itoa(int(onuID))
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001251}