blob: 95bc170260eac5ab7c87c5f9129bdd8cc415aefb [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"
kdarapu381c6902019-07-31 18:23:16 +053036 "github.com/opencord/voltha-go/adapters/adapterif"
cuilin20187b2a8c32019-03-26 19:52:28 -070037 "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
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
Mahir Gunyela3f9add2019-06-06 15:13:19 -070089}
90
91//NewOnuDevice creates a new Onu Device
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070092func NewOnuDevice(devID, deviceTp, serialNum string, onuID, intfID uint32, proxyDevID string) *OnuDevice {
Mahir Gunyela3f9add2019-06-06 15:13:19 -070093 var device OnuDevice
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070094 device.deviceID = devID
Mahir Gunyela3f9add2019-06-06 15:13:19 -070095 device.deviceType = deviceTp
96 device.serialNumber = serialNum
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070097 device.onuID = onuID
98 device.intfID = intfID
99 device.proxyDeviceID = proxyDevID
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700100 return &device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530101}
102
103//NewDeviceHandler creates a new device handler
kdarapu381c6902019-07-31 18:23:16 +0530104func NewDeviceHandler(cp adapterif.CoreProxy, ap adapterif.AdapterProxy, ep adapterif.EventProxy, device *voltha.Device, adapter *OpenOLT) *DeviceHandler {
cuilin20187b2a8c32019-03-26 19:52:28 -0700105 var dh DeviceHandler
106 dh.coreProxy = cp
Girish Gowdru0c588b22019-04-23 23:24:56 -0400107 dh.AdapterProxy = ap
Devmalya Paulfb990a52019-07-09 10:01:49 -0400108 dh.EventProxy = ep
cuilin20187b2a8c32019-03-26 19:52:28 -0700109 cloned := (proto.Clone(device)).(*voltha.Device)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700110 dh.deviceID = cloned.Id
cuilin20187b2a8c32019-03-26 19:52:28 -0700111 dh.deviceType = cloned.Type
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400112 dh.adminState = "up"
cuilin20187b2a8c32019-03-26 19:52:28 -0700113 dh.device = cloned
114 dh.openOLT = adapter
115 dh.exitChannel = make(chan int, 1)
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400116 dh.discOnus = make(map[string]bool)
cuilin20187b2a8c32019-03-26 19:52:28 -0700117 dh.lockDevice = sync.RWMutex{}
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700118 dh.onus = make(map[string]*OnuDevice)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700119 // The nniIntfID is initialized to -1 (invalid) and set to right value
Girish Gowdru1110ef22019-06-24 11:17:59 -0400120 // when the first IntfOperInd with status as "up" is received for
121 // any one of the available NNI port on the OLT device.
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700122 dh.nniIntfID = -1
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530123
cuilin20187b2a8c32019-03-26 19:52:28 -0700124 //TODO initialize the support classes.
125 return &dh
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530126}
127
128// start save the device to the data model
129func (dh *DeviceHandler) start(ctx context.Context) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700130 dh.lockDevice.Lock()
131 defer dh.lockDevice.Unlock()
132 log.Debugw("starting-device-agent", log.Fields{"device": dh.device})
133 // Add the initial device to the local model
134 log.Debug("device-agent-started")
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530135}
136
137// stop stops the device dh. Not much to do for now
138func (dh *DeviceHandler) stop(ctx context.Context) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700139 dh.lockDevice.Lock()
140 defer dh.lockDevice.Unlock()
141 log.Debug("stopping-device-agent")
142 dh.exitChannel <- 1
143 log.Debug("device-agent-stopped")
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530144}
145
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400146func macifyIP(ip net.IP) string {
147 if len(ip) > 0 {
148 oct1 := strconv.FormatInt(int64(ip[12]), 16)
149 oct2 := strconv.FormatInt(int64(ip[13]), 16)
150 oct3 := strconv.FormatInt(int64(ip[14]), 16)
151 oct4 := strconv.FormatInt(int64(ip[15]), 16)
152 return fmt.Sprintf("00:00:%02v:%02v:%02v:%02v", oct1, oct2, oct3, oct4)
153 }
154 return ""
155}
156
157func generateMacFromHost(host string) (string, error) {
158 var genmac string
159 var addr net.IP
160 var ips []string
161 var err error
162
163 log.Debugw("generating-mac-from-host", log.Fields{"host": host})
164
165 if addr = net.ParseIP(host); addr == nil {
166 log.Debugw("looking-up-hostname", log.Fields{"host": host})
167
168 if ips, err = net.LookupHost(host); err == nil {
169 log.Debugw("dns-result-ips", log.Fields{"ips": ips})
170 if addr = net.ParseIP(ips[0]); addr == nil {
171 log.Errorw("unable-to-parse-ip", log.Fields{"ip": ips[0]})
172 return "", errors.New("unable-to-parse-ip")
173 }
174 genmac = macifyIP(addr)
175 log.Debugw("using-ip-as-mac", log.Fields{"host": ips[0], "mac": genmac})
176 return genmac, nil
177 }
178 log.Errorw("cannot-resolve-hostname-to-ip", log.Fields{"host": host})
179 return "", err
180 }
181
182 genmac = macifyIP(addr)
183 log.Debugw("using-ip-as-mac", log.Fields{"host": host, "mac": genmac})
184 return genmac, nil
185}
186
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530187func macAddressToUint32Array(mac string) []uint32 {
cuilin20187b2a8c32019-03-26 19:52:28 -0700188 slist := strings.Split(mac, ":")
189 result := make([]uint32, len(slist))
190 var err error
191 var tmp int64
192 for index, val := range slist {
193 if tmp, err = strconv.ParseInt(val, 16, 32); err != nil {
194 return []uint32{1, 2, 3, 4, 5, 6}
195 }
196 result[index] = uint32(tmp)
197 }
198 return result
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530199}
200
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700201//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 +0530202func GetportLabel(portNum uint32, portType voltha.Port_PortType) string {
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530203
Girish Gowdru0c588b22019-04-23 23:24:56 -0400204 if portType == voltha.Port_ETHERNET_NNI {
205 return fmt.Sprintf("nni-%d", portNum)
206 } else if portType == voltha.Port_PON_OLT {
207 return fmt.Sprintf("pon-%d", portNum)
cuilin20187b2a8c32019-03-26 19:52:28 -0700208 } else if portType == voltha.Port_ETHERNET_UNI {
209 log.Errorw("local UNI management not supported", log.Fields{})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400210 return ""
cuilin20187b2a8c32019-03-26 19:52:28 -0700211 }
212 return ""
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530213}
214
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700215func (dh *DeviceHandler) addPort(intfID uint32, portType voltha.Port_PortType, state string) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700216 var operStatus common.OperStatus_OperStatus
217 if state == "up" {
218 operStatus = voltha.OperStatus_ACTIVE
219 } else {
220 operStatus = voltha.OperStatus_DISCOVERED
221 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700222 portNum := IntfIDToPortNo(intfID, portType)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400223 label := GetportLabel(portNum, portType)
224 if len(label) == 0 {
225 log.Errorw("Invalid-port-label", log.Fields{"portNum": portNum, "portType": portType})
226 return
227 }
228 // Now create Port
229 port := &voltha.Port{
cuilin20187b2a8c32019-03-26 19:52:28 -0700230 PortNo: portNum,
231 Label: label,
232 Type: portType,
233 OperStatus: operStatus,
234 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400235 log.Debugw("Sending port update to core", log.Fields{"port": port})
cuilin20187b2a8c32019-03-26 19:52:28 -0700236 // Synchronous call to update device - this method is run in its own go routine
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700237 if err := dh.coreProxy.PortCreated(context.TODO(), dh.device.Id, port); err != nil {
238 log.Errorw("error-creating-nni-port", log.Fields{"deviceID": dh.device.Id, "portType": portType, "error": err})
Girish Gowdru1110ef22019-06-24 11:17:59 -0400239 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700240
Girish Gowdru1110ef22019-06-24 11:17:59 -0400241 // Once we have successfully added the NNI port to the core, if the
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700242 // locally cached nniIntfID is set to invalid (-1), set it to the right value.
243 if portType == voltha.Port_ETHERNET_NNI && dh.nniIntfID == -1 {
244 dh.nniIntfID = int(intfID)
cuilin20187b2a8c32019-03-26 19:52:28 -0700245 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530246}
247
248// readIndications to read the indications from the OLT device
249func (dh *DeviceHandler) readIndications() {
William Kurkianff524662019-08-20 10:34:30 -0400250 defer log.Errorw("Indications ended", log.Fields{})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400251 indications, err := dh.Client.EnableIndication(context.Background(), new(oop.Empty))
cuilin20187b2a8c32019-03-26 19:52:28 -0700252 if err != nil {
253 log.Errorw("Failed to read indications", log.Fields{"err": err})
254 return
255 }
256 if indications == nil {
257 log.Errorw("Indications is nil", log.Fields{})
258 return
259 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400260 /* get device state */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700261 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400262 if err != nil || device == nil {
263 /*TODO: needs to handle error scenarios */
264 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700265 return
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400266 }
267 // When the device is in DISABLED and Adapter container restarts, we need to
268 // rebuild the locally maintained admin state.
269 if device.AdminState == voltha.AdminState_DISABLED {
270 dh.lockDevice.Lock()
271 dh.adminState = "down"
272 dh.lockDevice.Unlock()
273 }
274
cuilin20187b2a8c32019-03-26 19:52:28 -0700275 for {
276 indication, err := indications.Recv()
277 if err == io.EOF {
278 break
279 }
280 if err != nil {
281 log.Infow("Failed to read from indications", log.Fields{"err": err})
Devmalya Paul495b94a2019-08-27 19:42:00 -0400282 if dh.adminState == "deleted" {
283 log.Debug("Device deleted stoping the read indication thread")
284 break
285 }
Girish Gowdrud4245152019-05-10 00:47:31 -0400286 dh.transitionMap.Handle(DeviceDownInd)
287 dh.transitionMap.Handle(DeviceInit)
288 break
cuilin20187b2a8c32019-03-26 19:52:28 -0700289 }
Chaitrashree G S44124192019-08-07 20:21:36 -0400290 dh.lockDevice.RLock()
291 adminState := dh.adminState
292 dh.lockDevice.RUnlock()
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400293 // When OLT is admin down, allow only NNI operation status change indications.
Chaitrashree G S44124192019-08-07 20:21:36 -0400294 if adminState == "down" {
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400295 _, isIntfOperInd := indication.Data.(*oop.Indication_IntfOperInd)
296 if isIntfOperInd {
297 intfOperInd := indication.GetIntfOperInd()
298 if intfOperInd.GetType() == "nni" {
299 log.Infow("olt is admin down, allow nni ind", log.Fields{})
300 }
301 } else {
302 log.Infow("olt is admin down, ignore indication", log.Fields{})
303 continue
304 }
305 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530306
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700307 dh.handleIndication(indication)
manikkaraj kbf256be2019-03-25 00:13:48 +0530308
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700309 }
310}
311
312func (dh *DeviceHandler) handleOltIndication(oltIndication *oop.OltIndication) {
Daniele Rossi051466a2019-07-26 13:39:37 +0000313 raisedTs := time.Now().UnixNano()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700314 if oltIndication.OperState == "up" {
315 dh.transitionMap.Handle(DeviceUpInd)
316 } else if oltIndication.OperState == "down" {
317 dh.transitionMap.Handle(DeviceDownInd)
318 }
Daniele Rossi051466a2019-07-26 13:39:37 +0000319 // Send or clear Alarm
320 dh.eventMgr.oltUpDownIndication(oltIndication, dh.deviceID, raisedTs)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700321}
322
323func (dh *DeviceHandler) handleIndication(indication *oop.Indication) {
Devmalya Paulfb990a52019-07-09 10:01:49 -0400324 raisedTs := time.Now().UnixNano()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700325 switch indication.Data.(type) {
326 case *oop.Indication_OltInd:
327 dh.handleOltIndication(indication.GetOltInd())
328 case *oop.Indication_IntfInd:
329 intfInd := indication.GetIntfInd()
330 go dh.addPort(intfInd.GetIntfId(), voltha.Port_PON_OLT, intfInd.GetOperState())
331 log.Infow("Received interface indication ", log.Fields{"InterfaceInd": intfInd})
332 case *oop.Indication_IntfOperInd:
333 intfOperInd := indication.GetIntfOperInd()
334 if intfOperInd.GetType() == "nni" {
335 go dh.addPort(intfOperInd.GetIntfId(), voltha.Port_ETHERNET_NNI, intfOperInd.GetOperState())
336 } else if intfOperInd.GetType() == "pon" {
337 // TODO: Check what needs to be handled here for When PON PORT down, ONU will be down
338 // Handle pon port update
cuilin20187b2a8c32019-03-26 19:52:28 -0700339 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700340 log.Infow("Received interface oper indication ", log.Fields{"InterfaceOperInd": intfOperInd})
341 case *oop.Indication_OnuDiscInd:
342 onuDiscInd := indication.GetOnuDiscInd()
343 log.Infow("Received Onu discovery indication ", log.Fields{"OnuDiscInd": onuDiscInd})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700344 sn := dh.stringifySerialNumber(onuDiscInd.SerialNumber)
Matt Jeanneret53539512019-07-20 14:47:02 -0400345 go dh.onuDiscIndication(onuDiscInd, sn)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700346 case *oop.Indication_OnuInd:
347 onuInd := indication.GetOnuInd()
348 log.Infow("Received Onu indication ", log.Fields{"OnuInd": onuInd})
349 go dh.onuIndication(onuInd)
350 case *oop.Indication_OmciInd:
351 omciInd := indication.GetOmciInd()
352 log.Infow("Received Omci indication ", log.Fields{"OmciInd": omciInd})
William Kurkianff524662019-08-20 10:34:30 -0400353 go dh.omciIndication(omciInd)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700354 case *oop.Indication_PktInd:
355 pktInd := indication.GetPktInd()
356 log.Infow("Received pakcet indication ", log.Fields{"PktInd": pktInd})
357 go dh.handlePacketIndication(pktInd)
358 case *oop.Indication_PortStats:
359 portStats := indication.GetPortStats()
360 log.Infow("Received port stats indication", log.Fields{"PortStats": portStats})
361 case *oop.Indication_FlowStats:
362 flowStats := indication.GetFlowStats()
363 log.Infow("Received flow stats", log.Fields{"FlowStats": flowStats})
364 case *oop.Indication_AlarmInd:
365 alarmInd := indication.GetAlarmInd()
366 log.Infow("Received alarm indication ", log.Fields{"AlarmInd": alarmInd})
Devmalya Paulfb990a52019-07-09 10:01:49 -0400367 dh.eventMgr.ProcessEvents(alarmInd, dh.deviceID, raisedTs)
368
cuilin20187b2a8c32019-03-26 19:52:28 -0700369 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530370}
371
372// doStateUp handle the olt up indication and update to voltha core
373func (dh *DeviceHandler) doStateUp() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400374 // Synchronous call to update device state - this method is run in its own go routine
cuilin20187b2a8c32019-03-26 19:52:28 -0700375 if err := dh.coreProxy.DeviceStateUpdate(context.Background(), dh.device.Id, voltha.ConnectStatus_REACHABLE,
Girish Gowdru0c588b22019-04-23 23:24:56 -0400376 voltha.OperStatus_ACTIVE); err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700377 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 -0400378 return err
379 }
380 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530381}
382
383// doStateDown handle the olt down indication
384func (dh *DeviceHandler) doStateDown() error {
Girish Gowdrud4245152019-05-10 00:47:31 -0400385 log.Debug("do-state-down-start")
386
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700387 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400388 if err != nil || device == nil {
389 /*TODO: needs to handle error scenarios */
390 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700391 return errors.New("failed to fetch device device")
Girish Gowdrud4245152019-05-10 00:47:31 -0400392 }
393
394 cloned := proto.Clone(device).(*voltha.Device)
395 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700396 if er := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); er != nil {
397 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": er})
398 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400399 }
400
401 //Update the device oper state and connection status
402 cloned.OperStatus = voltha.OperStatus_UNKNOWN
403 cloned.ConnectStatus = common.ConnectStatus_UNREACHABLE
404 dh.device = cloned
405
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700406 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
407 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": er})
408 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400409 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400410
411 //get the child device for the parent device
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700412 onuDevices, err := dh.coreProxy.GetChildDevices(context.TODO(), dh.device.Id)
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400413 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700414 log.Errorw("failed to get child devices information", log.Fields{"deviceID": dh.device.Id, "error": err})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400415 return err
416 }
417 for _, onuDevice := range onuDevices.Items {
418
419 // Update onu state as down in onu adapter
420 onuInd := oop.OnuIndication{}
421 onuInd.OperState = "down"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700422 er := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), &onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
423 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
424 if er != nil {
425 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
426 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
427 return er
428 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400429 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700430 log.Debugw("do-state-down-end", log.Fields{"deviceID": device.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700431 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530432}
433
434// doStateInit dial the grpc before going to init state
435func (dh *DeviceHandler) doStateInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400436 var err error
Girish Gowdrud4245152019-05-10 00:47:31 -0400437 dh.clientCon, err = grpc.Dial(dh.device.GetHostAndPort(), grpc.WithInsecure(), grpc.WithBlock())
Girish Gowdru0c588b22019-04-23 23:24:56 -0400438 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700439 log.Errorw("Failed to dial device", log.Fields{"DeviceId": dh.deviceID, "HostAndPort": dh.device.GetHostAndPort(), "err": err})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400440 return err
441 }
442 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530443}
444
445// postInit create olt client instance to invoke RPC on the olt device
446func (dh *DeviceHandler) postInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400447 dh.Client = oop.NewOpenoltClient(dh.clientCon)
448 dh.transitionMap.Handle(GrpcConnected)
449 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530450}
451
452// doStateConnected get the device info and update to voltha core
453func (dh *DeviceHandler) doStateConnected() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400454 log.Debug("OLT device has been connected")
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400455
456 // Case where OLT is disabled and then rebooted.
457 if dh.adminState == "down" {
458 log.Debugln("do-state-connected--device-admin-state-down")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700459 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400460 if err != nil || device == nil {
461 /*TODO: needs to handle error scenarios */
462 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
463 }
464
465 cloned := proto.Clone(device).(*voltha.Device)
466 cloned.ConnectStatus = voltha.ConnectStatus_REACHABLE
467 cloned.OperStatus = voltha.OperStatus_UNKNOWN
468 dh.device = cloned
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700469 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
470 log.Errorw("error-updating-device-state", log.Fields{"deviceID": dh.device.Id, "error": er})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400471 }
472
Chaitrashree G S44124192019-08-07 20:21:36 -0400473 // 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 -0400474 _, err = dh.Client.DisableOlt(context.Background(), new(oop.Empty))
475 if err != nil {
476 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
477 }
478
479 // Start reading indications
480 go dh.readIndications()
481 return nil
482 }
483
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400484 deviceInfo, err := dh.populateDeviceInfo()
cuilin20187b2a8c32019-03-26 19:52:28 -0700485 if err != nil {
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400486 log.Errorw("Unable to populate Device Info", log.Fields{"err": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700487 return err
488 }
Girish Gowdrud4245152019-05-10 00:47:31 -0400489
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700490 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400491 if err != nil || device == nil {
492 /*TODO: needs to handle error scenarios */
493 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700494 return err
Girish Gowdrud4245152019-05-10 00:47:31 -0400495 }
496 cloned := proto.Clone(device).(*voltha.Device)
497 // Update the all ports (if available) on that device to ACTIVE.
498 // The ports do not normally exist, unless the device is coming back from a reboot
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700499 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
500 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdrud4245152019-05-10 00:47:31 -0400501 return err
502 }
503
Girish Gowdru0c588b22019-04-23 23:24:56 -0400504 KVStoreHostPort := fmt.Sprintf("%s:%d", dh.openOLT.KVStoreHost, dh.openOLT.KVStorePort)
505 // Instantiate resource manager
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700506 if dh.resourceMgr = rsrcMgr.NewResourceMgr(dh.deviceID, KVStoreHostPort, dh.openOLT.KVStoreType, dh.deviceType, deviceInfo); dh.resourceMgr == nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400507 log.Error("Error while instantiating resource manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700508 return errors.New("instantiating resource manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400509 }
510 // Instantiate flow manager
511 if dh.flowMgr = NewFlowManager(dh, dh.resourceMgr); dh.flowMgr == nil {
512 log.Error("Error while instantiating flow manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700513 return errors.New("instantiating flow manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400514 }
515 /* TODO: Instantiate Alarm , stats , BW managers */
Devmalya Paulfb990a52019-07-09 10:01:49 -0400516 /* Instantiating Event Manager to handle Alarms and KPIs */
517 dh.eventMgr = NewEventMgr(dh.EventProxy)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530518
cuilin20187b2a8c32019-03-26 19:52:28 -0700519 // Start reading indications
520 go dh.readIndications()
521 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530522}
523
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400524func (dh *DeviceHandler) populateDeviceInfo() (*oop.DeviceInfo, error) {
525 var err error
526 var deviceInfo *oop.DeviceInfo
527
528 deviceInfo, err = dh.Client.GetDeviceInfo(context.Background(), new(oop.Empty))
529
530 if err != nil {
531 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
532 return nil, err
533 }
534 if deviceInfo == nil {
535 log.Errorw("Device info is nil", log.Fields{})
536 return nil, errors.New("failed to get device info from OLT")
537 }
538
539 log.Debugw("Fetched device info", log.Fields{"deviceInfo": deviceInfo})
540 dh.device.Root = true
541 dh.device.Vendor = deviceInfo.Vendor
542 dh.device.Model = deviceInfo.Model
543 dh.device.SerialNumber = deviceInfo.DeviceSerialNumber
544 dh.device.HardwareVersion = deviceInfo.HardwareVersion
545 dh.device.FirmwareVersion = deviceInfo.FirmwareVersion
546
547 if deviceInfo.DeviceId == "" {
548 log.Warnw("no-device-id-provided-using-host", log.Fields{"hostport": dh.device.GetHostAndPort()})
549 host := strings.Split(dh.device.GetHostAndPort(), ":")[0]
550 genmac, err := generateMacFromHost(host)
551 if err != nil {
552 return nil, err
553 }
554 log.Debugw("using-host-for-mac-address", log.Fields{"host": host, "mac": genmac})
555 dh.device.MacAddress = genmac
556 } else {
557 dh.device.MacAddress = deviceInfo.DeviceId
558 }
559
560 // Synchronous call to update device - this method is run in its own go routine
561 if err := dh.coreProxy.DeviceUpdate(context.TODO(), dh.device); err != nil {
562 log.Errorw("error-updating-device", log.Fields{"deviceID": dh.device.Id, "error": err})
563 return nil, err
564 }
565
566 return deviceInfo, nil
567}
568
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700569//AdoptDevice adopts the OLT device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530570func (dh *DeviceHandler) AdoptDevice(device *voltha.Device) {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400571 dh.transitionMap = NewTransitionMap(dh)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700572 log.Infow("Adopt_device", log.Fields{"deviceID": device.Id, "Address": device.GetHostAndPort()})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400573 dh.transitionMap.Handle(DeviceInit)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530574}
575
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700576//GetOfpDeviceInfo Gets the Ofp information of the given device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530577func (dh *DeviceHandler) GetOfpDeviceInfo(device *voltha.Device) (*ic.SwitchCapability, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700578 return &ic.SwitchCapability{
579 Desc: &of.OfpDesc{
Devmalya Paul70dd4972019-06-10 15:19:17 +0530580 MfrDesc: "VOLTHA Project",
cuilin20187b2a8c32019-03-26 19:52:28 -0700581 HwDesc: "open_pon",
582 SwDesc: "open_pon",
583 SerialNum: dh.device.SerialNumber,
584 },
585 SwitchFeatures: &of.OfpSwitchFeatures{
586 NBuffers: 256,
587 NTables: 2,
588 Capabilities: uint32(of.OfpCapabilities_OFPC_FLOW_STATS |
589 of.OfpCapabilities_OFPC_TABLE_STATS |
590 of.OfpCapabilities_OFPC_PORT_STATS |
591 of.OfpCapabilities_OFPC_GROUP_STATS),
592 },
593 }, nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530594}
595
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700596//GetOfpPortInfo Get Ofp port information
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530597func (dh *DeviceHandler) GetOfpPortInfo(device *voltha.Device, portNo int64) (*ic.PortCapability, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700598 capacity := uint32(of.OfpPortFeatures_OFPPF_1GB_FD | of.OfpPortFeatures_OFPPF_FIBER)
cuilin20187b2a8c32019-03-26 19:52:28 -0700599 return &ic.PortCapability{
600 Port: &voltha.LogicalPort{
601 OfpPort: &of.OfpPort{
602 HwAddr: macAddressToUint32Array(dh.device.MacAddress),
603 Config: 0,
604 State: uint32(of.OfpPortState_OFPPS_LIVE),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700605 Curr: capacity,
606 Advertised: capacity,
607 Peer: capacity,
cuilin20187b2a8c32019-03-26 19:52:28 -0700608 CurrSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
609 MaxSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
610 },
611 DeviceId: dh.device.Id,
612 DevicePortNo: uint32(portNo),
613 },
614 }, nil
615}
616
William Kurkianff524662019-08-20 10:34:30 -0400617func (dh *DeviceHandler) omciIndication(omciInd *oop.OmciIndication) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700618 log.Debugw("omci indication", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700619 var deviceType string
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700620 var deviceID string
621 var proxyDeviceID string
cuilin20187b2a8c32019-03-26 19:52:28 -0700622
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700623 onuKey := dh.formOnuKey(omciInd.IntfId, omciInd.OnuId)
624 if onuInCache, ok := dh.onus[onuKey]; !ok {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700625 log.Debugw("omci indication for a device not in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
626 ponPort := IntfIDToPortNo(omciInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700627 kwargs := make(map[string]interface{})
628 kwargs["onu_id"] = omciInd.OnuId
629 kwargs["parent_port_no"] = ponPort
cuilin20187b2a8c32019-03-26 19:52:28 -0700630
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700631 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
632 if err != nil {
William Kurkianff524662019-08-20 10:34:30 -0400633 log.Errorw("onu not found", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId, "error": err})
634 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700635 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700636 deviceType = onuDevice.Type
637 deviceID = onuDevice.Id
638 proxyDeviceID = onuDevice.ProxyAddress.DeviceId
639 //if not exist in cache, then add to cache.
640 dh.onus[onuKey] = NewOnuDevice(deviceID, deviceType, onuDevice.SerialNumber, omciInd.OnuId, omciInd.IntfId, proxyDeviceID)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700641 } else {
642 //found in cache
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700643 log.Debugw("omci indication for a device in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700644 deviceType = onuInCache.deviceType
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700645 deviceID = onuInCache.deviceID
646 proxyDeviceID = onuInCache.proxyDeviceID
cuilin20187b2a8c32019-03-26 19:52:28 -0700647 }
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700648
649 omciMsg := &ic.InterAdapterOmciMessage{Message: omciInd.Pkt}
650 if sendErr := dh.AdapterProxy.SendInterAdapterMessage(context.Background(), omciMsg,
651 ic.InterAdapterMessageType_OMCI_REQUEST, dh.deviceType, deviceType,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700652 deviceID, proxyDeviceID, ""); sendErr != nil {
William Kurkianff524662019-08-20 10:34:30 -0400653 log.Errorw("send omci request error", log.Fields{"fromAdapter": dh.deviceType, "toAdapter": deviceType, "onuID": deviceID, "proxyDeviceID": proxyDeviceID, "error": sendErr})
654 return
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700655 }
William Kurkianff524662019-08-20 10:34:30 -0400656 return
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530657}
658
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700659//ProcessInterAdapterMessage sends the proxied messages to the target device
660// If the proxy address is not found in the unmarshalled message, it first fetches the onu device for which the message
661// is meant, and then send the unmarshalled omci message to this onu
662func (dh *DeviceHandler) ProcessInterAdapterMessage(msg *ic.InterAdapterMessage) error {
663 log.Debugw("Process_inter_adapter_message", log.Fields{"msgID": msg.Header.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700664 if msg.Header.Type == ic.InterAdapterMessageType_OMCI_REQUEST {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700665 msgID := msg.Header.Id
cuilin20187b2a8c32019-03-26 19:52:28 -0700666 fromTopic := msg.Header.FromTopic
667 toTopic := msg.Header.ToTopic
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700668 toDeviceID := msg.Header.ToDeviceId
669 proxyDeviceID := msg.Header.ProxyDeviceId
cuilin20187b2a8c32019-03-26 19:52:28 -0700670
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700671 log.Debugw("omci request message header", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700672
673 msgBody := msg.GetBody()
674
675 omciMsg := &ic.InterAdapterOmciMessage{}
676 if err := ptypes.UnmarshalAny(msgBody, omciMsg); err != nil {
677 log.Warnw("cannot-unmarshal-omci-msg-body", log.Fields{"error": err})
678 return err
679 }
680
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700681 if omciMsg.GetProxyAddress() == nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700682 onuDevice, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, toDeviceID)
683 if err != nil {
684 log.Errorw("onu not found", log.Fields{"onuDeviceId": toDeviceID, "error": err})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700685 return err
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700686 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700687 log.Debugw("device retrieved from core", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
688 dh.sendProxiedMessage(onuDevice, omciMsg)
689
cuilin20187b2a8c32019-03-26 19:52:28 -0700690 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700691 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 -0700692 dh.sendProxiedMessage(nil, omciMsg)
cuilin20187b2a8c32019-03-26 19:52:28 -0700693 }
694
695 } else {
696 log.Errorw("inter-adapter-unhandled-type", log.Fields{"msgType": msg.Header.Type})
697 }
698 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530699}
700
cuilin20187b2a8c32019-03-26 19:52:28 -0700701func (dh *DeviceHandler) sendProxiedMessage(onuDevice *voltha.Device, omciMsg *ic.InterAdapterOmciMessage) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700702 var intfID uint32
703 var onuID uint32
704 var connectStatus common.ConnectStatus_ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700705 if onuDevice != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700706 intfID = onuDevice.ProxyAddress.GetChannelId()
707 onuID = onuDevice.ProxyAddress.GetOnuId()
708 connectStatus = onuDevice.ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700709 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700710 intfID = omciMsg.GetProxyAddress().GetChannelId()
711 onuID = omciMsg.GetProxyAddress().GetOnuId()
712 connectStatus = omciMsg.GetConnectStatus()
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700713 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700714 if connectStatus != voltha.ConnectStatus_REACHABLE {
715 log.Debugw("ONU is not reachable, cannot send OMCI", log.Fields{"intfID": intfID, "onuID": onuID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700716 return
717 }
718
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700719 omciMessage := &oop.OmciMsg{IntfId: intfID, OnuId: onuID, Pkt: omciMsg.Message}
cuilin20187b2a8c32019-03-26 19:52:28 -0700720
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700721 _, err := dh.Client.OmciMsgOut(context.Background(), omciMessage)
722 if err != nil {
723 log.Errorw("unable to send omci-msg-out", log.Fields{"IntfID": intfID, "OnuID": onuID, "Msg": omciMessage})
724 return
725 }
726 log.Debugw("omci-message-sent", log.Fields{"intfID": intfID, "onuID": onuID, "omciMsg": string(omciMsg.GetMessage())})
cuilin20187b2a8c32019-03-26 19:52:28 -0700727}
728
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700729func (dh *DeviceHandler) activateONU(intfID uint32, onuID int64, serialNum *oop.SerialNumber, serialNumber string) {
730 log.Debugw("activate-onu", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum, "serialNumber": serialNumber})
731 dh.flowMgr.UpdateOnuInfo(intfID, uint32(onuID), serialNumber)
cuilin20187b2a8c32019-03-26 19:52:28 -0700732 // TODO: need resource manager
733 var pir uint32 = 1000000
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700734 Onu := oop.Onu{IntfId: intfID, OnuId: uint32(onuID), SerialNumber: serialNum, Pir: pir}
manikkaraj kbf256be2019-03-25 00:13:48 +0530735 if _, err := dh.Client.ActivateOnu(context.Background(), &Onu); err != nil {
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400736 st, _ := status.FromError(err)
737 if st.Code() == codes.AlreadyExists {
738 log.Debug("ONU activation is in progress", log.Fields{"SerialNumber": serialNumber})
739 } else {
740 log.Errorw("activate-onu-failed", log.Fields{"Onu": Onu, "err ": err})
741 }
cuilin20187b2a8c32019-03-26 19:52:28 -0700742 } else {
743 log.Infow("activated-onu", log.Fields{"SerialNumber": serialNumber})
744 }
745}
746
Matt Jeanneret53539512019-07-20 14:47:02 -0400747func (dh *DeviceHandler) onuDiscIndication(onuDiscInd *oop.OnuDiscIndication, sn string) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700748 channelID := onuDiscInd.GetIntfId()
749 parentPortNo := IntfIDToPortNo(onuDiscInd.GetIntfId(), voltha.Port_PON_OLT)
Matt Jeanneret53539512019-07-20 14:47:02 -0400750
751 log.Debugw("new-discovery-indication", log.Fields{"sn": sn})
752 dh.lockDevice.Lock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400753 if _, ok := dh.discOnus[sn]; ok {
Matt Jeanneret53539512019-07-20 14:47:02 -0400754 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400755 log.Debugw("onu-sn-is-already-being-processed", log.Fields{"sn": sn})
Matt Jeanneret53539512019-07-20 14:47:02 -0400756 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700757 }
758
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400759 dh.discOnus[sn] = true
Matt Jeanneret53539512019-07-20 14:47:02 -0400760 log.Debugw("new-discovery-indications-list", log.Fields{"discOnus": dh.discOnus})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400761 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400762
cuilin20187b2a8c32019-03-26 19:52:28 -0700763 kwargs := make(map[string]interface{})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400764 if sn != "" {
765 kwargs["serial_number"] = sn
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400766 } else {
Matt Jeanneret53539512019-07-20 14:47:02 -0400767 log.Errorw("invalid onu serial number", log.Fields{"sn": sn})
768 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400769 }
770
771 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
772 var onuID uint32
773 if onuDevice == nil || err != nil {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700774 //This is the first time ONU discovered. Create an OnuID for it.
Matt Jeanneret53539512019-07-20 14:47:02 -0400775 ponintfid := onuDiscInd.GetIntfId()
776 dh.lockDevice.Lock()
777 onuID, err = dh.resourceMgr.GetONUID(ponintfid)
778 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400779 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400780 log.Errorw("failed to fetch onuID from resource manager", log.Fields{"pon-intf-id": ponintfid, "err": err})
781 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400782 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700783 if onuDevice, err = dh.coreProxy.ChildDeviceDetected(context.TODO(), dh.device.Id, int(parentPortNo),
Chaitrashree G See824a22019-07-28 18:28:27 -0400784 "", int(channelID),
Mahir Gunyele77977b2019-06-27 05:36:22 -0700785 string(onuDiscInd.SerialNumber.GetVendorId()), sn, int64(onuID)); onuDevice == nil {
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400786 log.Errorw("Create onu error",
787 log.Fields{"parent_id": dh.device.Id, "ponPort": onuDiscInd.GetIntfId(),
788 "onuID": onuID, "sn": sn, "error": err})
Matt Jeanneret53539512019-07-20 14:47:02 -0400789 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400790 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400791 log.Debugw("onu-child-device-added", log.Fields{"onuDevice": onuDevice})
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400792
793 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700794 //ONU already discovered before. Use the same OnuID.
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400795 onuID = onuDevice.ProxyAddress.OnuId
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400796 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700797 //Insert the ONU into cache to use in OnuIndication.
798 //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 -0700799 log.Debugw("ONU discovery indication key create", log.Fields{"onuID": onuID,
800 "intfId": onuDiscInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700801 onuKey := dh.formOnuKey(onuDiscInd.GetIntfId(), onuID)
Matt Jeanneret53539512019-07-20 14:47:02 -0400802
803 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700804 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuID, onuDiscInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400805 log.Debugw("new-onu-device-discovered", log.Fields{"onu": dh.onus[onuKey]})
806 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400807
Mahir Gunyele77977b2019-06-27 05:36:22 -0700808 err = dh.coreProxy.DeviceStateUpdate(context.TODO(), onuDevice.Id, common.ConnectStatus_REACHABLE, common.OperStatus_DISCOVERED)
809 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400810 log.Errorw("failed to update device state", log.Fields{"DeviceID": onuDevice.Id, "err": err})
811 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700812 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700813 log.Debugw("onu-discovered-reachable", log.Fields{"deviceId": onuDevice.Id})
814 //TODO: We put this sleep here to prevent the race between state update and onuIndication
815 //In onuIndication the operStatus of device is checked. If it is still not updated in KV store
816 //then the initialisation fails.
817 time.Sleep(1 * time.Second)
818 dh.activateONU(onuDiscInd.IntfId, int64(onuID), onuDiscInd.SerialNumber, sn)
Matt Jeanneret53539512019-07-20 14:47:02 -0400819 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700820}
821
822func (dh *DeviceHandler) onuIndication(onuInd *oop.OnuIndication) {
823 serialNumber := dh.stringifySerialNumber(onuInd.SerialNumber)
824
825 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700826 ponPort := IntfIDToPortNo(onuInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyele77977b2019-06-27 05:36:22 -0700827 var onuDevice *voltha.Device
828 foundInCache := false
Scott Baker7eb0a932019-07-26 10:33:22 -0700829 log.Debugw("ONU indication key create", log.Fields{"onuId": onuInd.OnuId,
830 "intfId": onuInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700831 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.OnuId)
832 if onuInCache, ok := dh.onus[onuKey]; ok {
833 //If ONU id is discovered before then use GetDevice to get onuDevice because it is cheaper.
834 foundInCache = true
835 onuDevice, _ = dh.coreProxy.GetDevice(nil, dh.device.Id, onuInCache.deviceID)
cuilin20187b2a8c32019-03-26 19:52:28 -0700836 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700837 //If ONU not found in adapter cache then we have to use GetChildDevice to get onuDevice
838 if serialNumber != "" {
839 kwargs["serial_number"] = serialNumber
840 } else {
841 kwargs["onu_id"] = onuInd.OnuId
842 kwargs["parent_port_no"] = ponPort
843 }
844 onuDevice, _ = dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
cuilin20187b2a8c32019-03-26 19:52:28 -0700845 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700846
847 if onuDevice != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400848 if onuDevice.ParentPortNo != ponPort {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700849 //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 -0400850 log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": onuDevice.ParentPortNo, "currentIntfId": ponPort})
cuilin20187b2a8c32019-03-26 19:52:28 -0700851 }
852
853 if onuDevice.ProxyAddress.OnuId != onuInd.OnuId {
854 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})
855 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700856 if !foundInCache {
857 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.GetOnuId())
Matt Jeanneret53539512019-07-20 14:47:02 -0400858 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700859 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuInd.GetOnuId(), onuInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400860 dh.lockDevice.Unlock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700861 }
Scott Baker7eb0a932019-07-26 10:33:22 -0700862 dh.updateOnuStates(onuDevice, onuInd, foundInCache)
cuilin20187b2a8c32019-03-26 19:52:28 -0700863
cuilin20187b2a8c32019-03-26 19:52:28 -0700864 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700865 log.Errorw("onu not found", log.Fields{"intfID": onuInd.IntfId, "onuID": onuInd.OnuId})
cuilin20187b2a8c32019-03-26 19:52:28 -0700866 return
867 }
868
869}
870
Scott Baker7eb0a932019-07-26 10:33:22 -0700871func (dh *DeviceHandler) updateOnuStates(onuDevice *voltha.Device, onuInd *oop.OnuIndication, foundInCache bool) {
Matt Jeanneret53539512019-07-20 14:47:02 -0400872 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 -0700873 dh.updateOnuAdminState(onuInd)
874 // operState
875 if onuInd.OperState == "down" {
Matt Jeanneret53539512019-07-20 14:47:02 -0400876 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 -0700877 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
878 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
879 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
880 if err != nil {
881 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
882 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
883 }
884 } else if onuInd.OperState == "up" {
Scott Baker7eb0a932019-07-26 10:33:22 -0700885 // Ignore operstatus if device was found in cache
886 if !foundInCache && onuDevice.OperStatus != common.OperStatus_DISCOVERED {
Matt Jeanneret53539512019-07-20 14:47:02 -0400887 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 -0700888 return
889 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400890 log.Debugw("sending-interadapter-onu-indication", log.Fields{"onuIndication": onuInd, "DeviceId": onuDevice.Id, "operStatus": onuDevice.OperStatus, "adminStatus": onuDevice.AdminState})
891 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700892 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
893 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
894 if err != nil {
895 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
896 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
897 return
898 }
899 } else {
900 log.Warnw("Not-implemented-or-invalid-value-of-oper-state", log.Fields{"operState": onuInd.OperState})
901 }
902}
903
904func (dh *DeviceHandler) updateOnuAdminState(onuInd *oop.OnuIndication) {
905 if onuInd.AdminState == "down" {
906 if onuInd.OperState != "down" {
907 log.Errorw("ONU-admin-state-down-and-oper-status-not-down", log.Fields{"operState": onuInd.OperState})
908 // Forcing the oper state change code to execute
909 onuInd.OperState = "down"
910 }
911 // Port and logical port update is taken care of by oper state block
912 } else if onuInd.AdminState == "up" {
913 log.Debugln("received-onu-admin-state up")
914 } else {
915 log.Errorw("Invalid-or-not-implemented-admin-state", log.Fields{"received-admin-state": onuInd.AdminState})
916 }
917 log.Debugln("admin-state-dealt-with")
918}
919
cuilin20187b2a8c32019-03-26 19:52:28 -0700920func (dh *DeviceHandler) stringifySerialNumber(serialNum *oop.SerialNumber) string {
921 if serialNum != nil {
922 return string(serialNum.VendorId) + dh.stringifyVendorSpecific(serialNum.VendorSpecific)
cuilin20187b2a8c32019-03-26 19:52:28 -0700923 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700924 return ""
cuilin20187b2a8c32019-03-26 19:52:28 -0700925}
926
927func (dh *DeviceHandler) stringifyVendorSpecific(vendorSpecific []byte) string {
928 tmp := fmt.Sprintf("%x", (uint32(vendorSpecific[0])>>4)&0x0f) +
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700929 fmt.Sprintf("%x", uint32(vendorSpecific[0]&0x0f)) +
cuilin20187b2a8c32019-03-26 19:52:28 -0700930 fmt.Sprintf("%x", (uint32(vendorSpecific[1])>>4)&0x0f) +
931 fmt.Sprintf("%x", (uint32(vendorSpecific[1]))&0x0f) +
932 fmt.Sprintf("%x", (uint32(vendorSpecific[2])>>4)&0x0f) +
933 fmt.Sprintf("%x", (uint32(vendorSpecific[2]))&0x0f) +
934 fmt.Sprintf("%x", (uint32(vendorSpecific[3])>>4)&0x0f) +
935 fmt.Sprintf("%x", (uint32(vendorSpecific[3]))&0x0f)
936 return tmp
937}
938
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700939//UpdateFlowsBulk upates the bulk flow
940func (dh *DeviceHandler) UpdateFlowsBulk() error {
941 return errors.New("unimplemented")
cuilin20187b2a8c32019-03-26 19:52:28 -0700942}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700943
944//GetChildDevice returns the child device for given parent port and onu id
945func (dh *DeviceHandler) GetChildDevice(parentPort, onuID uint32) *voltha.Device {
946 log.Debugw("GetChildDevice", log.Fields{"pon port": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400947 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700948 kwargs["onu_id"] = onuID
Girish Gowdru0c588b22019-04-23 23:24:56 -0400949 kwargs["parent_port_no"] = parentPort
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700950 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400951 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700952 log.Errorw("onu not found", log.Fields{"intfID": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400953 return nil
954 }
955 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
956 return onuDevice
manikkaraj kbf256be2019-03-25 00:13:48 +0530957}
958
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700959// SendPacketInToCore sends packet-in to core
960// For this, it calls SendPacketIn of the core-proxy which uses a device specific topic to send the request.
961// The adapter handling the device creates a device specific topic
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400962func (dh *DeviceHandler) SendPacketInToCore(logicalPort uint32, packetPayload []byte) {
963 log.Debugw("SendPacketInToCore", log.Fields{"port": logicalPort, "packetPayload": packetPayload})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700964 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPort, packetPayload); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400965 log.Errorw("Error sending packetin to core", log.Fields{"error": err})
966 return
967 }
968 log.Debug("Sent packet-in to core successfully")
969}
970
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700971//UpdateFlowsIncrementally updates the device flow
Manikkaraj kb1d51442019-07-23 10:41:02 -0400972func (dh *DeviceHandler) UpdateFlowsIncrementally(device *voltha.Device, flows *of.FlowChanges, groups *of.FlowGroupChanges, flowMetadata *voltha.FlowMetadata) error {
973 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 -0400974 if flows != nil {
975 for _, flow := range flows.ToAdd.Items {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400976 log.Debug("Adding flow", log.Fields{"deviceId": device.Id, "flowToAdd": flow})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400977 dh.flowMgr.AddFlow(flow, flowMetadata)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400978 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400979 for _, flow := range flows.ToRemove.Items {
980 log.Debug("Removing flow", log.Fields{"deviceId": device.Id, "flowToRemove": flow})
981 dh.flowMgr.RemoveFlow(flow)
982 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400983 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700984 if groups != nil && flows != nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400985 for _, flow := range flows.ToRemove.Items {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700986 log.Debug("Removing flow", log.Fields{"deviceID": device.Id, "flowToRemove": flow})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400987 // dh.flowMgr.RemoveFlow(flow)
988 }
989 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400990 log.Debug("UpdateFlowsIncrementally done successfully")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400991 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530992}
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400993
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700994//DisableDevice disables the given device
995//It marks the following for the given device:
996//Device-Handler Admin-State : down
997//Device Port-State: UNKNOWN
998//Device Oper-State: UNKNOWN
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400999func (dh *DeviceHandler) DisableDevice(device *voltha.Device) error {
Chaitrashree G S44124192019-08-07 20:21:36 -04001000 /* On device disable ,admin state update has to be done prior sending request to agent since
1001 the indication thread may processes invalid indications of ONU and OLT*/
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001002 dh.lockDevice.Lock()
1003 dh.adminState = "down"
1004 dh.lockDevice.Unlock()
Chaitrashree G S44124192019-08-07 20:21:36 -04001005 if _, err := dh.Client.DisableOlt(context.Background(), new(oop.Empty)); err != nil {
1006 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
1007 dh.lockDevice.Lock()
1008 dh.adminState = "up"
1009 dh.lockDevice.Unlock()
1010 return err
1011 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001012 log.Debug("olt-disabled")
Chaitrashree G S44124192019-08-07 20:21:36 -04001013 dh.lockDevice.Lock()
1014 /* Discovered ONUs entries need to be cleared , since on device disable the child devices goes to
1015 UNREACHABLE state which needs to be configured again*/
1016 dh.discOnus = make(map[string]bool)
1017 dh.lockDevice.Unlock()
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001018
1019 cloned := proto.Clone(device).(*voltha.Device)
1020 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001021 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); err != nil {
1022 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001023 return err
1024 }
1025
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001026 log.Debugw("Disable_device-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001027 return nil
1028}
1029
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001030//ReenableDevice re-enables the olt device after disable
1031//It marks the following for the given device:
1032//Device-Handler Admin-State : up
1033//Device Port-State: ACTIVE
1034//Device Oper-State: ACTIVE
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001035func (dh *DeviceHandler) ReenableDevice(device *voltha.Device) error {
1036 if _, err := dh.Client.ReenableOlt(context.Background(), new(oop.Empty)); err != nil {
1037 log.Errorw("Failed to reenable olt ", log.Fields{"err": err})
1038 return err
1039 }
1040
1041 dh.lockDevice.Lock()
1042 dh.adminState = "up"
1043 dh.lockDevice.Unlock()
1044 log.Debug("olt-reenabled")
1045
1046 cloned := proto.Clone(device).(*voltha.Device)
1047 // Update the all ports state on that device to enable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001048 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
1049 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001050 return err
1051 }
1052
1053 //Update the device oper status as ACTIVE
1054 cloned.OperStatus = voltha.OperStatus_ACTIVE
1055 dh.device = cloned
1056
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001057 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1058 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001059 return err
1060 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001061 log.Debugw("ReEnableDevice-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001062
1063 return nil
1064}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001065
Devmalya Paul495b94a2019-08-27 19:42:00 -04001066func (dh *DeviceHandler) clearUNIData(onu *OnuDevice, uniPorts []*voltha.Port) error {
1067 var uniID uint32
1068 var err error
1069 for _, port := range uniPorts {
1070 if port.Type == voltha.Port_ETHERNET_UNI {
1071 uniID = UniIDFromPortNum(port.PortNo)
1072 /* Delete tech-profile instance from the KV store */
1073 if err = dh.flowMgr.DeleteTechProfileInstance(onu.intfID, onu.onuID, uniID, onu.serialNumber); err != nil {
1074 log.Debugw("Failed-to-remove-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
1075 }
1076 log.Debugw("Deleted-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
1077 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(onu.intfID, onu.onuID, uniID)
1078 for _, flowID := range flowIDs {
1079 dh.resourceMgr.FreeFlowID(onu.intfID, int32(onu.onuID), int32(uniID), flowID)
1080 }
1081 dh.resourceMgr.FreePONResourcesForONU(onu.intfID, onu.onuID, uniID)
1082 if err = dh.resourceMgr.RemoveTechProfileIDForOnu(onu.intfID, onu.onuID, uniID); err != nil {
1083 log.Debugw("Failed-to-remove-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1084 }
1085 log.Debugw("Removed-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1086 if err = dh.resourceMgr.RemoveMeterIDForOnu("upstream", onu.intfID, onu.onuID, uniID); err != nil {
1087 log.Debugw("Failed-to-remove-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1088 }
1089 log.Debugw("Removed-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1090 if err = dh.resourceMgr.RemoveMeterIDForOnu("downstream", onu.intfID, onu.onuID, uniID); err != nil {
1091 log.Debugw("Failed-to-remove-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
1092 }
1093 log.Debugw("Removed-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
1094 }
1095 }
1096 return nil
1097}
1098
1099func (dh *DeviceHandler) clearNNIData() error {
1100 nniUniID := -1
1101 nniOnuID := -1
1102 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1103 log.Debugw("Current flow ids for nni", log.Fields{"flow-ids": flowIDs})
1104 for _, flowID := range flowIDs {
1105 dh.resourceMgr.FreeFlowID(uint32(dh.nniIntfID), -1, -1, uint32(flowID))
1106 }
1107 //Free the flow-ids for the NNI port
1108 dh.resourceMgr.FreePONResourcesForONU(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1109 /* Free ONU IDs for each pon port
1110 intfIDToONUIds is a map of intf-id: [onu-ids]*/
1111 intfIDToONUIds := make(map[uint32][]uint32)
1112 for _, onu := range dh.onus {
1113 intfIDToONUIds[onu.intfID] = append(intfIDToONUIds[onu.intfID], onu.onuID)
1114 }
1115 for intfID, onuIds := range intfIDToONUIds {
1116 dh.resourceMgr.FreeonuID(intfID, onuIds)
1117 }
1118 return nil
1119}
1120
1121// DeleteDevice deletes the device instance from openolt handler array. Also clears allocated resource manager resources. Also reboots the OLT hardware!
1122func (dh *DeviceHandler) DeleteDevice(device *voltha.Device) error {
1123 log.Debug("Function entry delete device")
1124 dh.lockDevice.Lock()
1125 dh.adminState = "deleted"
1126 dh.lockDevice.Unlock()
1127 /* Clear the KV store data associated with the all the UNI ports
1128 This clears up flow data and also resource map data for various
1129 other pon resources like alloc_id and gemport_id
1130 */
1131 for _, onu := range dh.onus {
1132 childDevice, err := dh.coreProxy.GetDevice(nil, dh.deviceID, onu.deviceID)
1133 if err != nil {
1134 log.Debug("Failed to get onu device")
1135 continue
1136 }
1137 uniPorts := childDevice.Ports
1138 log.Debugw("onu-uni-ports", log.Fields{"onu-ports": uniPorts})
1139 if err := dh.clearUNIData(onu, uniPorts); err != nil {
1140 log.Debugw("Failed to clear data for onu", log.Fields{"onu-device": onu})
1141 }
1142 }
1143 /* Clear the flows from KV store associated with NNI port.
1144 There are mostly trap rules from NNI port (like LLDP)
1145 */
1146 if err := dh.clearNNIData(); err != nil {
1147 log.Debugw("Failed to clear data for NNI port", log.Fields{"device-id": dh.deviceID})
1148 }
1149 /* Clear the resource pool for each PON port*/
1150 if err := dh.resourceMgr.Delete(); err != nil {
1151 log.Debug("Failed-to-remove-device-from-Resource-mananger-KV-store")
1152 }
1153 /*Delete ONU map for the device*/
1154 for onu := range dh.onus {
1155 delete(dh.onus, onu)
1156 }
1157 log.Debug("Removed-device-from-Resource-manager-KV-store")
1158 //Reset the state
1159 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1160 log.Errorw("Failed-to-reboot-olt ", log.Fields{"err": err})
1161 return err
1162 }
1163 cloned := proto.Clone(device).(*voltha.Device)
1164 cloned.OperStatus = voltha.OperStatus_UNKNOWN
1165 cloned.ConnectStatus = voltha.ConnectStatus_UNREACHABLE
1166 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1167 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
1168 return err
1169 }
1170 return nil
1171}
1172
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001173//RebootDevice reboots the given device
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001174func (dh *DeviceHandler) RebootDevice(device *voltha.Device) error {
1175 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1176 log.Errorw("Failed to reboot olt ", log.Fields{"err": err})
1177 return err
1178 }
1179
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001180 log.Debugw("rebooted-device-successfully", log.Fields{"deviceID": device.Id})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001181
1182 return nil
1183}
1184
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001185func (dh *DeviceHandler) handlePacketIndication(packetIn *oop.PacketIndication) {
1186 log.Debugw("Received packet-in", log.Fields{"packet-indication": *packetIn})
1187 logicalPortNum, err := dh.flowMgr.GetLogicalPortFromPacketIn(packetIn)
1188 if err != nil {
1189 log.Errorw("Error getting logical port from packet-in", log.Fields{"error": err})
1190 return
1191 }
1192 log.Debugw("sending packet-in to core", log.Fields{"logicalPortNum": logicalPortNum, "packet": *packetIn})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001193 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPortNum, packetIn.Pkt); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001194 log.Errorw("Error sending packet-in to core", log.Fields{"error": err})
1195 return
1196 }
1197 log.Debug("Success sending packet-in to core!")
1198}
1199
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001200// PacketOut sends packet-out from VOLTHA to OLT on the egress port provided
1201func (dh *DeviceHandler) PacketOut(egressPortNo int, packet *of.OfpPacketOut) error {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001202 log.Debugw("incoming-packet-out", log.Fields{"deviceID": dh.deviceID, "egress_port_no": egressPortNo,
1203 "pkt-length": len(packet.Data), "packetData": hex.EncodeToString(packet.Data)})
1204
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001205 egressPortType := IntfIDToPortTypeName(uint32(egressPortNo))
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001206 if egressPortType == voltha.Port_ETHERNET_UNI {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001207 outerEthType := (uint16(packet.Data[12]) << 8) | uint16(packet.Data[13])
1208 innerEthType := (uint16(packet.Data[16]) << 8) | uint16(packet.Data[17])
1209 if outerEthType == 0x88a8 || outerEthType == 0x8100 {
1210 if innerEthType == 0x8100 {
1211 // q-in-q 802.1ad or 802.1q double tagged packet.
1212 // slice out the outer tag.
1213 packet.Data = append(packet.Data[:12], packet.Data[16:]...)
1214 log.Debugw("packet-now-single-tagged", log.Fields{"packetData": hex.EncodeToString(packet.Data)})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001215 }
1216 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001217 intfID := IntfIDFromUniPortNum(uint32(egressPortNo))
1218 onuID := OnuIDFromPortNum(uint32(egressPortNo))
Manikkaraj kb1d51442019-07-23 10:41:02 -04001219 uniID := UniIDFromPortNum(uint32(egressPortNo))
1220
1221 gemPortID, err := dh.flowMgr.GetPacketOutGemPortID(intfID, onuID, uint32(egressPortNo))
1222 if err != nil {
1223 // In this case the openolt agent will receive the gemPortID as 0.
1224 // The agent tries to retrieve the gemPortID in this case.
1225 // This may not always succeed at the agent and packetOut may fail.
1226 log.Error("failed-to-retrieve-gemport-id-for-packet-out")
1227 }
1228
1229 onuPkt := oop.OnuPacket{IntfId: intfID, OnuId: onuID, PortNo: uint32(egressPortNo), GemportId: gemPortID, Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001230
1231 log.Debugw("sending-packet-to-onu", log.Fields{"egress_port_no": egressPortNo, "IntfId": intfID, "onuID": onuID,
Manikkaraj kb1d51442019-07-23 10:41:02 -04001232 "uniID": uniID, "gemPortID": gemPortID, "packet": hex.EncodeToString(packet.Data)})
Matt Jeanneret1359c732019-08-01 21:40:02 -04001233
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001234 if _, err := dh.Client.OnuPacketOut(context.Background(), &onuPkt); err != nil {
1235 log.Errorw("Error while sending packet-out to ONU", log.Fields{"error": err})
1236 return err
1237 }
1238 } else if egressPortType == voltha.Port_ETHERNET_NNI {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001239 uplinkPkt := oop.UplinkPacket{IntfId: IntfIDFromNniPortNum(uint32(egressPortNo)), Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001240
1241 log.Debugw("sending-packet-to-nni", log.Fields{"uplink_pkt": uplinkPkt, "packet": hex.EncodeToString(packet.Data)})
1242
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001243 if _, err := dh.Client.UplinkPacketOut(context.Background(), &uplinkPkt); err != nil {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001244 log.Errorw("Error while sending packet-out to NNI", log.Fields{"error": err})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001245 return err
1246 }
1247 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001248 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 -04001249 }
1250 return nil
1251}
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001252
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001253func (dh *DeviceHandler) formOnuKey(intfID, onuID uint32) string {
1254 return "" + strconv.Itoa(int(intfID)) + "." + strconv.Itoa(int(onuID))
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001255}