blob: 3ba09679d73dddfbb31f683d89b6f599f2a6c03f [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"
kdarapub67f49c2019-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
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
kdarapub67f49c2019-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
kdarapub67f49c2019-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
kdarapub67f49c2019-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 Kurkian294a78b2019-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 Pauleb2e9552019-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()
Gamze Abakafe85c2e2019-10-10 12:27:51 +0000314 if oltIndication.OperState == "up" && dh.transitionMap.currentDeviceState != deviceStateUp {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700315 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
Gamze Abakaa9958252019-10-10 12:29:53 +0000339 go dh.addPort(intfOperInd.GetIntfId(), voltha.Port_PON_OLT, intfOperInd.GetOperState())
cuilin20187b2a8c32019-03-26 19:52:28 -0700340 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700341 log.Infow("Received interface oper indication ", log.Fields{"InterfaceOperInd": intfOperInd})
342 case *oop.Indication_OnuDiscInd:
343 onuDiscInd := indication.GetOnuDiscInd()
344 log.Infow("Received Onu discovery indication ", log.Fields{"OnuDiscInd": onuDiscInd})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700345 sn := dh.stringifySerialNumber(onuDiscInd.SerialNumber)
Matt Jeanneret53539512019-07-20 14:47:02 -0400346 go dh.onuDiscIndication(onuDiscInd, sn)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700347 case *oop.Indication_OnuInd:
348 onuInd := indication.GetOnuInd()
349 log.Infow("Received Onu indication ", log.Fields{"OnuInd": onuInd})
350 go dh.onuIndication(onuInd)
351 case *oop.Indication_OmciInd:
352 omciInd := indication.GetOmciInd()
353 log.Infow("Received Omci indication ", log.Fields{"OmciInd": omciInd})
William Kurkian294a78b2019-08-20 10:34:30 -0400354 go dh.omciIndication(omciInd)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700355 case *oop.Indication_PktInd:
356 pktInd := indication.GetPktInd()
357 log.Infow("Received pakcet indication ", log.Fields{"PktInd": pktInd})
358 go dh.handlePacketIndication(pktInd)
359 case *oop.Indication_PortStats:
360 portStats := indication.GetPortStats()
361 log.Infow("Received port stats indication", log.Fields{"PortStats": portStats})
362 case *oop.Indication_FlowStats:
363 flowStats := indication.GetFlowStats()
364 log.Infow("Received flow stats", log.Fields{"FlowStats": flowStats})
365 case *oop.Indication_AlarmInd:
366 alarmInd := indication.GetAlarmInd()
367 log.Infow("Received alarm indication ", log.Fields{"AlarmInd": alarmInd})
Devmalya Paulfb990a52019-07-09 10:01:49 -0400368 dh.eventMgr.ProcessEvents(alarmInd, dh.deviceID, raisedTs)
369
cuilin20187b2a8c32019-03-26 19:52:28 -0700370 }
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530371}
372
373// doStateUp handle the olt up indication and update to voltha core
374func (dh *DeviceHandler) doStateUp() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400375 // Synchronous call to update device state - this method is run in its own go routine
cuilin20187b2a8c32019-03-26 19:52:28 -0700376 if err := dh.coreProxy.DeviceStateUpdate(context.Background(), dh.device.Id, voltha.ConnectStatus_REACHABLE,
Girish Gowdru0c588b22019-04-23 23:24:56 -0400377 voltha.OperStatus_ACTIVE); err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700378 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 -0400379 return err
380 }
381 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530382}
383
384// doStateDown handle the olt down indication
385func (dh *DeviceHandler) doStateDown() error {
serkant.uluderya88701b02019-09-24 23:15:29 -0700386 dh.lockDevice.Lock()
387 defer dh.lockDevice.Unlock()
Girish Gowdrud4245152019-05-10 00:47:31 -0400388 log.Debug("do-state-down-start")
389
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700390 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400391 if err != nil || device == nil {
392 /*TODO: needs to handle error scenarios */
393 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700394 return errors.New("failed to fetch device device")
Girish Gowdrud4245152019-05-10 00:47:31 -0400395 }
396
397 cloned := proto.Clone(device).(*voltha.Device)
398 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700399 if er := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); er != nil {
400 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": er})
401 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400402 }
403
404 //Update the device oper state and connection status
405 cloned.OperStatus = voltha.OperStatus_UNKNOWN
406 cloned.ConnectStatus = common.ConnectStatus_UNREACHABLE
407 dh.device = cloned
408
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700409 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
410 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": er})
411 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400412 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400413
414 //get the child device for the parent device
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700415 onuDevices, err := dh.coreProxy.GetChildDevices(context.TODO(), dh.device.Id)
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400416 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700417 log.Errorw("failed to get child devices information", log.Fields{"deviceID": dh.device.Id, "error": err})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400418 return err
419 }
420 for _, onuDevice := range onuDevices.Items {
421
422 // Update onu state as down in onu adapter
423 onuInd := oop.OnuIndication{}
424 onuInd.OperState = "down"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700425 er := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), &onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
426 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
427 if er != nil {
428 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
429 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
serkant.uluderya88701b02019-09-24 23:15:29 -0700430 //Do not return here and continue to process other ONUs
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700431 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400432 }
serkant.uluderya88701b02019-09-24 23:15:29 -0700433 /* Discovered ONUs entries need to be cleared , since after OLT
434 is up, it starts sending discovery indications again*/
435 dh.discOnus = make(map[string]bool)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700436 log.Debugw("do-state-down-end", log.Fields{"deviceID": device.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700437 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530438}
439
440// doStateInit dial the grpc before going to init state
441func (dh *DeviceHandler) doStateInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400442 var err error
Girish Gowdrud4245152019-05-10 00:47:31 -0400443 dh.clientCon, err = grpc.Dial(dh.device.GetHostAndPort(), grpc.WithInsecure(), grpc.WithBlock())
Girish Gowdru0c588b22019-04-23 23:24:56 -0400444 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700445 log.Errorw("Failed to dial device", log.Fields{"DeviceId": dh.deviceID, "HostAndPort": dh.device.GetHostAndPort(), "err": err})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400446 return err
447 }
448 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530449}
450
451// postInit create olt client instance to invoke RPC on the olt device
452func (dh *DeviceHandler) postInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400453 dh.Client = oop.NewOpenoltClient(dh.clientCon)
454 dh.transitionMap.Handle(GrpcConnected)
455 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530456}
457
458// doStateConnected get the device info and update to voltha core
459func (dh *DeviceHandler) doStateConnected() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400460 log.Debug("OLT device has been connected")
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400461
462 // Case where OLT is disabled and then rebooted.
463 if dh.adminState == "down" {
464 log.Debugln("do-state-connected--device-admin-state-down")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700465 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400466 if err != nil || device == nil {
467 /*TODO: needs to handle error scenarios */
468 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
469 }
470
471 cloned := proto.Clone(device).(*voltha.Device)
472 cloned.ConnectStatus = voltha.ConnectStatus_REACHABLE
473 cloned.OperStatus = voltha.OperStatus_UNKNOWN
474 dh.device = cloned
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700475 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
476 log.Errorw("error-updating-device-state", log.Fields{"deviceID": dh.device.Id, "error": er})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400477 }
478
Chaitrashree G S44124192019-08-07 20:21:36 -0400479 // 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 -0400480 _, err = dh.Client.DisableOlt(context.Background(), new(oop.Empty))
481 if err != nil {
482 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
483 }
484
485 // Start reading indications
486 go dh.readIndications()
487 return nil
488 }
489
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400490 deviceInfo, err := dh.populateDeviceInfo()
cuilin20187b2a8c32019-03-26 19:52:28 -0700491 if err != nil {
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400492 log.Errorw("Unable to populate Device Info", log.Fields{"err": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700493 return err
494 }
Girish Gowdrud4245152019-05-10 00:47:31 -0400495
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700496 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400497 if err != nil || device == nil {
498 /*TODO: needs to handle error scenarios */
499 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700500 return err
Girish Gowdrud4245152019-05-10 00:47:31 -0400501 }
502 cloned := proto.Clone(device).(*voltha.Device)
503 // Update the all ports (if available) on that device to ACTIVE.
504 // The ports do not normally exist, unless the device is coming back from a reboot
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700505 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
506 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdrud4245152019-05-10 00:47:31 -0400507 return err
508 }
509
Girish Gowdru0c588b22019-04-23 23:24:56 -0400510 KVStoreHostPort := fmt.Sprintf("%s:%d", dh.openOLT.KVStoreHost, dh.openOLT.KVStorePort)
511 // Instantiate resource manager
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700512 if dh.resourceMgr = rsrcMgr.NewResourceMgr(dh.deviceID, KVStoreHostPort, dh.openOLT.KVStoreType, dh.deviceType, deviceInfo); dh.resourceMgr == nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400513 log.Error("Error while instantiating resource manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700514 return errors.New("instantiating resource manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400515 }
516 // Instantiate flow manager
517 if dh.flowMgr = NewFlowManager(dh, dh.resourceMgr); dh.flowMgr == nil {
518 log.Error("Error while instantiating flow manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700519 return errors.New("instantiating flow manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400520 }
521 /* TODO: Instantiate Alarm , stats , BW managers */
Devmalya Paulfb990a52019-07-09 10:01:49 -0400522 /* Instantiating Event Manager to handle Alarms and KPIs */
Devmalya Paul2b87f5a2019-09-02 21:55:45 -0400523 dh.eventMgr = NewEventMgr(dh.EventProxy, dh)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530524
cuilin20187b2a8c32019-03-26 19:52:28 -0700525 // Start reading indications
526 go dh.readIndications()
527 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530528}
529
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400530func (dh *DeviceHandler) populateDeviceInfo() (*oop.DeviceInfo, error) {
531 var err error
532 var deviceInfo *oop.DeviceInfo
533
534 deviceInfo, err = dh.Client.GetDeviceInfo(context.Background(), new(oop.Empty))
535
536 if err != nil {
537 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
538 return nil, err
539 }
540 if deviceInfo == nil {
541 log.Errorw("Device info is nil", log.Fields{})
542 return nil, errors.New("failed to get device info from OLT")
543 }
544
545 log.Debugw("Fetched device info", log.Fields{"deviceInfo": deviceInfo})
546 dh.device.Root = true
547 dh.device.Vendor = deviceInfo.Vendor
548 dh.device.Model = deviceInfo.Model
549 dh.device.SerialNumber = deviceInfo.DeviceSerialNumber
550 dh.device.HardwareVersion = deviceInfo.HardwareVersion
551 dh.device.FirmwareVersion = deviceInfo.FirmwareVersion
552
553 if deviceInfo.DeviceId == "" {
554 log.Warnw("no-device-id-provided-using-host", log.Fields{"hostport": dh.device.GetHostAndPort()})
555 host := strings.Split(dh.device.GetHostAndPort(), ":")[0]
556 genmac, err := generateMacFromHost(host)
557 if err != nil {
558 return nil, err
559 }
560 log.Debugw("using-host-for-mac-address", log.Fields{"host": host, "mac": genmac})
561 dh.device.MacAddress = genmac
562 } else {
563 dh.device.MacAddress = deviceInfo.DeviceId
564 }
565
566 // Synchronous call to update device - this method is run in its own go routine
567 if err := dh.coreProxy.DeviceUpdate(context.TODO(), dh.device); err != nil {
568 log.Errorw("error-updating-device", log.Fields{"deviceID": dh.device.Id, "error": err})
569 return nil, err
570 }
571
572 return deviceInfo, nil
573}
574
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700575//AdoptDevice adopts the OLT device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530576func (dh *DeviceHandler) AdoptDevice(device *voltha.Device) {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400577 dh.transitionMap = NewTransitionMap(dh)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700578 log.Infow("Adopt_device", log.Fields{"deviceID": device.Id, "Address": device.GetHostAndPort()})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400579 dh.transitionMap.Handle(DeviceInit)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530580}
581
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700582//GetOfpDeviceInfo Gets the Ofp information of the given device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530583func (dh *DeviceHandler) GetOfpDeviceInfo(device *voltha.Device) (*ic.SwitchCapability, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700584 return &ic.SwitchCapability{
585 Desc: &of.OfpDesc{
Devmalya Paul70dd4972019-06-10 15:19:17 +0530586 MfrDesc: "VOLTHA Project",
cuilin20187b2a8c32019-03-26 19:52:28 -0700587 HwDesc: "open_pon",
588 SwDesc: "open_pon",
589 SerialNum: dh.device.SerialNumber,
590 },
591 SwitchFeatures: &of.OfpSwitchFeatures{
592 NBuffers: 256,
593 NTables: 2,
594 Capabilities: uint32(of.OfpCapabilities_OFPC_FLOW_STATS |
595 of.OfpCapabilities_OFPC_TABLE_STATS |
596 of.OfpCapabilities_OFPC_PORT_STATS |
597 of.OfpCapabilities_OFPC_GROUP_STATS),
598 },
599 }, nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530600}
601
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700602//GetOfpPortInfo Get Ofp port information
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530603func (dh *DeviceHandler) GetOfpPortInfo(device *voltha.Device, portNo int64) (*ic.PortCapability, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700604 capacity := uint32(of.OfpPortFeatures_OFPPF_1GB_FD | of.OfpPortFeatures_OFPPF_FIBER)
cuilin20187b2a8c32019-03-26 19:52:28 -0700605 return &ic.PortCapability{
606 Port: &voltha.LogicalPort{
607 OfpPort: &of.OfpPort{
608 HwAddr: macAddressToUint32Array(dh.device.MacAddress),
609 Config: 0,
610 State: uint32(of.OfpPortState_OFPPS_LIVE),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700611 Curr: capacity,
612 Advertised: capacity,
613 Peer: capacity,
cuilin20187b2a8c32019-03-26 19:52:28 -0700614 CurrSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
615 MaxSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
616 },
617 DeviceId: dh.device.Id,
618 DevicePortNo: uint32(portNo),
619 },
620 }, nil
621}
622
William Kurkian294a78b2019-08-20 10:34:30 -0400623func (dh *DeviceHandler) omciIndication(omciInd *oop.OmciIndication) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700624 log.Debugw("omci indication", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700625 var deviceType string
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700626 var deviceID string
627 var proxyDeviceID string
cuilin20187b2a8c32019-03-26 19:52:28 -0700628
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700629 onuKey := dh.formOnuKey(omciInd.IntfId, omciInd.OnuId)
630 if onuInCache, ok := dh.onus[onuKey]; !ok {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700631 log.Debugw("omci indication for a device not in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
632 ponPort := IntfIDToPortNo(omciInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700633 kwargs := make(map[string]interface{})
634 kwargs["onu_id"] = omciInd.OnuId
635 kwargs["parent_port_no"] = ponPort
cuilin20187b2a8c32019-03-26 19:52:28 -0700636
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700637 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
638 if err != nil {
William Kurkian294a78b2019-08-20 10:34:30 -0400639 log.Errorw("onu not found", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId, "error": err})
640 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700641 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700642 deviceType = onuDevice.Type
643 deviceID = onuDevice.Id
644 proxyDeviceID = onuDevice.ProxyAddress.DeviceId
645 //if not exist in cache, then add to cache.
646 dh.onus[onuKey] = NewOnuDevice(deviceID, deviceType, onuDevice.SerialNumber, omciInd.OnuId, omciInd.IntfId, proxyDeviceID)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700647 } else {
648 //found in cache
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700649 log.Debugw("omci indication for a device in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700650 deviceType = onuInCache.deviceType
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700651 deviceID = onuInCache.deviceID
652 proxyDeviceID = onuInCache.proxyDeviceID
cuilin20187b2a8c32019-03-26 19:52:28 -0700653 }
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700654
655 omciMsg := &ic.InterAdapterOmciMessage{Message: omciInd.Pkt}
656 if sendErr := dh.AdapterProxy.SendInterAdapterMessage(context.Background(), omciMsg,
657 ic.InterAdapterMessageType_OMCI_REQUEST, dh.deviceType, deviceType,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700658 deviceID, proxyDeviceID, ""); sendErr != nil {
William Kurkian294a78b2019-08-20 10:34:30 -0400659 log.Errorw("send omci request error", log.Fields{"fromAdapter": dh.deviceType, "toAdapter": deviceType, "onuID": deviceID, "proxyDeviceID": proxyDeviceID, "error": sendErr})
660 return
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700661 }
William Kurkian294a78b2019-08-20 10:34:30 -0400662 return
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530663}
664
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700665//ProcessInterAdapterMessage sends the proxied messages to the target device
666// If the proxy address is not found in the unmarshalled message, it first fetches the onu device for which the message
667// is meant, and then send the unmarshalled omci message to this onu
668func (dh *DeviceHandler) ProcessInterAdapterMessage(msg *ic.InterAdapterMessage) error {
669 log.Debugw("Process_inter_adapter_message", log.Fields{"msgID": msg.Header.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700670 if msg.Header.Type == ic.InterAdapterMessageType_OMCI_REQUEST {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700671 msgID := msg.Header.Id
cuilin20187b2a8c32019-03-26 19:52:28 -0700672 fromTopic := msg.Header.FromTopic
673 toTopic := msg.Header.ToTopic
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700674 toDeviceID := msg.Header.ToDeviceId
675 proxyDeviceID := msg.Header.ProxyDeviceId
cuilin20187b2a8c32019-03-26 19:52:28 -0700676
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700677 log.Debugw("omci request message header", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700678
679 msgBody := msg.GetBody()
680
681 omciMsg := &ic.InterAdapterOmciMessage{}
682 if err := ptypes.UnmarshalAny(msgBody, omciMsg); err != nil {
683 log.Warnw("cannot-unmarshal-omci-msg-body", log.Fields{"error": err})
684 return err
685 }
686
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700687 if omciMsg.GetProxyAddress() == nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700688 onuDevice, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, toDeviceID)
689 if err != nil {
690 log.Errorw("onu not found", log.Fields{"onuDeviceId": toDeviceID, "error": err})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700691 return err
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700692 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700693 log.Debugw("device retrieved from core", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
694 dh.sendProxiedMessage(onuDevice, omciMsg)
695
cuilin20187b2a8c32019-03-26 19:52:28 -0700696 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700697 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 -0700698 dh.sendProxiedMessage(nil, omciMsg)
cuilin20187b2a8c32019-03-26 19:52:28 -0700699 }
700
701 } else {
702 log.Errorw("inter-adapter-unhandled-type", log.Fields{"msgType": msg.Header.Type})
703 }
704 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530705}
706
cuilin20187b2a8c32019-03-26 19:52:28 -0700707func (dh *DeviceHandler) sendProxiedMessage(onuDevice *voltha.Device, omciMsg *ic.InterAdapterOmciMessage) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700708 var intfID uint32
709 var onuID uint32
710 var connectStatus common.ConnectStatus_ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700711 if onuDevice != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700712 intfID = onuDevice.ProxyAddress.GetChannelId()
713 onuID = onuDevice.ProxyAddress.GetOnuId()
714 connectStatus = onuDevice.ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700715 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700716 intfID = omciMsg.GetProxyAddress().GetChannelId()
717 onuID = omciMsg.GetProxyAddress().GetOnuId()
718 connectStatus = omciMsg.GetConnectStatus()
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700719 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700720 if connectStatus != voltha.ConnectStatus_REACHABLE {
721 log.Debugw("ONU is not reachable, cannot send OMCI", log.Fields{"intfID": intfID, "onuID": onuID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700722 return
723 }
724
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700725 omciMessage := &oop.OmciMsg{IntfId: intfID, OnuId: onuID, Pkt: omciMsg.Message}
cuilin20187b2a8c32019-03-26 19:52:28 -0700726
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700727 _, err := dh.Client.OmciMsgOut(context.Background(), omciMessage)
728 if err != nil {
729 log.Errorw("unable to send omci-msg-out", log.Fields{"IntfID": intfID, "OnuID": onuID, "Msg": omciMessage})
730 return
731 }
732 log.Debugw("omci-message-sent", log.Fields{"intfID": intfID, "onuID": onuID, "omciMsg": string(omciMsg.GetMessage())})
cuilin20187b2a8c32019-03-26 19:52:28 -0700733}
734
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700735func (dh *DeviceHandler) activateONU(intfID uint32, onuID int64, serialNum *oop.SerialNumber, serialNumber string) {
736 log.Debugw("activate-onu", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum, "serialNumber": serialNumber})
737 dh.flowMgr.UpdateOnuInfo(intfID, uint32(onuID), serialNumber)
cuilin20187b2a8c32019-03-26 19:52:28 -0700738 // TODO: need resource manager
739 var pir uint32 = 1000000
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700740 Onu := oop.Onu{IntfId: intfID, OnuId: uint32(onuID), SerialNumber: serialNum, Pir: pir}
manikkaraj kbf256be2019-03-25 00:13:48 +0530741 if _, err := dh.Client.ActivateOnu(context.Background(), &Onu); err != nil {
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400742 st, _ := status.FromError(err)
743 if st.Code() == codes.AlreadyExists {
744 log.Debug("ONU activation is in progress", log.Fields{"SerialNumber": serialNumber})
745 } else {
746 log.Errorw("activate-onu-failed", log.Fields{"Onu": Onu, "err ": err})
747 }
cuilin20187b2a8c32019-03-26 19:52:28 -0700748 } else {
749 log.Infow("activated-onu", log.Fields{"SerialNumber": serialNumber})
750 }
751}
752
Matt Jeanneret53539512019-07-20 14:47:02 -0400753func (dh *DeviceHandler) onuDiscIndication(onuDiscInd *oop.OnuDiscIndication, sn string) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700754 channelID := onuDiscInd.GetIntfId()
755 parentPortNo := IntfIDToPortNo(onuDiscInd.GetIntfId(), voltha.Port_PON_OLT)
Matt Jeanneret53539512019-07-20 14:47:02 -0400756
757 log.Debugw("new-discovery-indication", log.Fields{"sn": sn})
758 dh.lockDevice.Lock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400759 if _, ok := dh.discOnus[sn]; ok {
Matt Jeanneret53539512019-07-20 14:47:02 -0400760 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400761 log.Debugw("onu-sn-is-already-being-processed", log.Fields{"sn": sn})
Matt Jeanneret53539512019-07-20 14:47:02 -0400762 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700763 }
764
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400765 dh.discOnus[sn] = true
Matt Jeanneret53539512019-07-20 14:47:02 -0400766 log.Debugw("new-discovery-indications-list", log.Fields{"discOnus": dh.discOnus})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400767 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400768
cuilin20187b2a8c32019-03-26 19:52:28 -0700769 kwargs := make(map[string]interface{})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400770 if sn != "" {
771 kwargs["serial_number"] = sn
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400772 } else {
Matt Jeanneret53539512019-07-20 14:47:02 -0400773 log.Errorw("invalid onu serial number", log.Fields{"sn": sn})
774 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400775 }
776
777 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
778 var onuID uint32
779 if onuDevice == nil || err != nil {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700780 //This is the first time ONU discovered. Create an OnuID for it.
Matt Jeanneret53539512019-07-20 14:47:02 -0400781 ponintfid := onuDiscInd.GetIntfId()
782 dh.lockDevice.Lock()
783 onuID, err = dh.resourceMgr.GetONUID(ponintfid)
784 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400785 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400786 log.Errorw("failed to fetch onuID from resource manager", log.Fields{"pon-intf-id": ponintfid, "err": err})
787 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400788 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700789 if onuDevice, err = dh.coreProxy.ChildDeviceDetected(context.TODO(), dh.device.Id, int(parentPortNo),
Chaitrashree G See824a22019-07-28 18:28:27 -0400790 "", int(channelID),
Mahir Gunyele77977b2019-06-27 05:36:22 -0700791 string(onuDiscInd.SerialNumber.GetVendorId()), sn, int64(onuID)); onuDevice == nil {
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400792 log.Errorw("Create onu error",
793 log.Fields{"parent_id": dh.device.Id, "ponPort": onuDiscInd.GetIntfId(),
794 "onuID": onuID, "sn": sn, "error": err})
Matt Jeanneret53539512019-07-20 14:47:02 -0400795 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400796 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400797 log.Debugw("onu-child-device-added", log.Fields{"onuDevice": onuDevice})
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400798
799 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700800 //ONU already discovered before. Use the same OnuID.
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400801 onuID = onuDevice.ProxyAddress.OnuId
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400802 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700803 //Insert the ONU into cache to use in OnuIndication.
804 //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 -0700805 log.Debugw("ONU discovery indication key create", log.Fields{"onuID": onuID,
806 "intfId": onuDiscInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700807 onuKey := dh.formOnuKey(onuDiscInd.GetIntfId(), onuID)
Matt Jeanneret53539512019-07-20 14:47:02 -0400808
809 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700810 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuID, onuDiscInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400811 log.Debugw("new-onu-device-discovered", log.Fields{"onu": dh.onus[onuKey]})
812 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400813
Mahir Gunyele77977b2019-06-27 05:36:22 -0700814 err = dh.coreProxy.DeviceStateUpdate(context.TODO(), onuDevice.Id, common.ConnectStatus_REACHABLE, common.OperStatus_DISCOVERED)
815 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400816 log.Errorw("failed to update device state", log.Fields{"DeviceID": onuDevice.Id, "err": err})
817 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700818 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700819 log.Debugw("onu-discovered-reachable", log.Fields{"deviceId": onuDevice.Id})
820 //TODO: We put this sleep here to prevent the race between state update and onuIndication
821 //In onuIndication the operStatus of device is checked. If it is still not updated in KV store
822 //then the initialisation fails.
823 time.Sleep(1 * time.Second)
824 dh.activateONU(onuDiscInd.IntfId, int64(onuID), onuDiscInd.SerialNumber, sn)
Matt Jeanneret53539512019-07-20 14:47:02 -0400825 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700826}
827
828func (dh *DeviceHandler) onuIndication(onuInd *oop.OnuIndication) {
829 serialNumber := dh.stringifySerialNumber(onuInd.SerialNumber)
830
831 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700832 ponPort := IntfIDToPortNo(onuInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyele77977b2019-06-27 05:36:22 -0700833 var onuDevice *voltha.Device
834 foundInCache := false
Scott Baker7eb0a932019-07-26 10:33:22 -0700835 log.Debugw("ONU indication key create", log.Fields{"onuId": onuInd.OnuId,
836 "intfId": onuInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700837 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.OnuId)
838 if onuInCache, ok := dh.onus[onuKey]; ok {
839 //If ONU id is discovered before then use GetDevice to get onuDevice because it is cheaper.
840 foundInCache = true
841 onuDevice, _ = dh.coreProxy.GetDevice(nil, dh.device.Id, onuInCache.deviceID)
cuilin20187b2a8c32019-03-26 19:52:28 -0700842 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700843 //If ONU not found in adapter cache then we have to use GetChildDevice to get onuDevice
844 if serialNumber != "" {
845 kwargs["serial_number"] = serialNumber
846 } else {
847 kwargs["onu_id"] = onuInd.OnuId
848 kwargs["parent_port_no"] = ponPort
849 }
850 onuDevice, _ = dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
cuilin20187b2a8c32019-03-26 19:52:28 -0700851 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700852
853 if onuDevice != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400854 if onuDevice.ParentPortNo != ponPort {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700855 //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 -0400856 log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": onuDevice.ParentPortNo, "currentIntfId": ponPort})
cuilin20187b2a8c32019-03-26 19:52:28 -0700857 }
858
859 if onuDevice.ProxyAddress.OnuId != onuInd.OnuId {
860 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})
861 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700862 if !foundInCache {
863 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.GetOnuId())
Matt Jeanneret53539512019-07-20 14:47:02 -0400864 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700865 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuInd.GetOnuId(), onuInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400866 dh.lockDevice.Unlock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700867 }
Scott Baker7eb0a932019-07-26 10:33:22 -0700868 dh.updateOnuStates(onuDevice, onuInd, foundInCache)
cuilin20187b2a8c32019-03-26 19:52:28 -0700869
cuilin20187b2a8c32019-03-26 19:52:28 -0700870 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700871 log.Errorw("onu not found", log.Fields{"intfID": onuInd.IntfId, "onuID": onuInd.OnuId})
cuilin20187b2a8c32019-03-26 19:52:28 -0700872 return
873 }
874
875}
876
Scott Baker7eb0a932019-07-26 10:33:22 -0700877func (dh *DeviceHandler) updateOnuStates(onuDevice *voltha.Device, onuInd *oop.OnuIndication, foundInCache bool) {
Matt Jeanneret53539512019-07-20 14:47:02 -0400878 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 -0700879 dh.updateOnuAdminState(onuInd)
880 // operState
881 if onuInd.OperState == "down" {
Matt Jeanneret53539512019-07-20 14:47:02 -0400882 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 -0700883 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
884 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
885 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
886 if err != nil {
887 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
888 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
889 }
890 } else if onuInd.OperState == "up" {
Scott Baker7eb0a932019-07-26 10:33:22 -0700891 // Ignore operstatus if device was found in cache
892 if !foundInCache && onuDevice.OperStatus != common.OperStatus_DISCOVERED {
Matt Jeanneret53539512019-07-20 14:47:02 -0400893 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 -0700894 return
895 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400896 log.Debugw("sending-interadapter-onu-indication", log.Fields{"onuIndication": onuInd, "DeviceId": onuDevice.Id, "operStatus": onuDevice.OperStatus, "adminStatus": onuDevice.AdminState})
897 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700898 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
899 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
900 if err != nil {
901 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
902 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
903 return
904 }
905 } else {
906 log.Warnw("Not-implemented-or-invalid-value-of-oper-state", log.Fields{"operState": onuInd.OperState})
907 }
908}
909
910func (dh *DeviceHandler) updateOnuAdminState(onuInd *oop.OnuIndication) {
911 if onuInd.AdminState == "down" {
912 if onuInd.OperState != "down" {
913 log.Errorw("ONU-admin-state-down-and-oper-status-not-down", log.Fields{"operState": onuInd.OperState})
914 // Forcing the oper state change code to execute
915 onuInd.OperState = "down"
916 }
917 // Port and logical port update is taken care of by oper state block
918 } else if onuInd.AdminState == "up" {
919 log.Debugln("received-onu-admin-state up")
920 } else {
921 log.Errorw("Invalid-or-not-implemented-admin-state", log.Fields{"received-admin-state": onuInd.AdminState})
922 }
923 log.Debugln("admin-state-dealt-with")
924}
925
cuilin20187b2a8c32019-03-26 19:52:28 -0700926func (dh *DeviceHandler) stringifySerialNumber(serialNum *oop.SerialNumber) string {
927 if serialNum != nil {
928 return string(serialNum.VendorId) + dh.stringifyVendorSpecific(serialNum.VendorSpecific)
cuilin20187b2a8c32019-03-26 19:52:28 -0700929 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700930 return ""
cuilin20187b2a8c32019-03-26 19:52:28 -0700931}
932
933func (dh *DeviceHandler) stringifyVendorSpecific(vendorSpecific []byte) string {
934 tmp := fmt.Sprintf("%x", (uint32(vendorSpecific[0])>>4)&0x0f) +
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700935 fmt.Sprintf("%x", uint32(vendorSpecific[0]&0x0f)) +
cuilin20187b2a8c32019-03-26 19:52:28 -0700936 fmt.Sprintf("%x", (uint32(vendorSpecific[1])>>4)&0x0f) +
937 fmt.Sprintf("%x", (uint32(vendorSpecific[1]))&0x0f) +
938 fmt.Sprintf("%x", (uint32(vendorSpecific[2])>>4)&0x0f) +
939 fmt.Sprintf("%x", (uint32(vendorSpecific[2]))&0x0f) +
940 fmt.Sprintf("%x", (uint32(vendorSpecific[3])>>4)&0x0f) +
941 fmt.Sprintf("%x", (uint32(vendorSpecific[3]))&0x0f)
942 return tmp
943}
944
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700945//UpdateFlowsBulk upates the bulk flow
946func (dh *DeviceHandler) UpdateFlowsBulk() error {
947 return errors.New("unimplemented")
cuilin20187b2a8c32019-03-26 19:52:28 -0700948}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700949
950//GetChildDevice returns the child device for given parent port and onu id
951func (dh *DeviceHandler) GetChildDevice(parentPort, onuID uint32) *voltha.Device {
952 log.Debugw("GetChildDevice", log.Fields{"pon port": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400953 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700954 kwargs["onu_id"] = onuID
Girish Gowdru0c588b22019-04-23 23:24:56 -0400955 kwargs["parent_port_no"] = parentPort
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700956 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400957 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700958 log.Errorw("onu not found", log.Fields{"intfID": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400959 return nil
960 }
961 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
962 return onuDevice
manikkaraj kbf256be2019-03-25 00:13:48 +0530963}
964
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700965// SendPacketInToCore sends packet-in to core
966// For this, it calls SendPacketIn of the core-proxy which uses a device specific topic to send the request.
967// The adapter handling the device creates a device specific topic
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400968func (dh *DeviceHandler) SendPacketInToCore(logicalPort uint32, packetPayload []byte) {
969 log.Debugw("SendPacketInToCore", log.Fields{"port": logicalPort, "packetPayload": packetPayload})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700970 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPort, packetPayload); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400971 log.Errorw("Error sending packetin to core", log.Fields{"error": err})
972 return
973 }
974 log.Debug("Sent packet-in to core successfully")
975}
976
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700977//UpdateFlowsIncrementally updates the device flow
Manikkaraj kb1d51442019-07-23 10:41:02 -0400978func (dh *DeviceHandler) UpdateFlowsIncrementally(device *voltha.Device, flows *of.FlowChanges, groups *of.FlowGroupChanges, flowMetadata *voltha.FlowMetadata) error {
979 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 -0400980 if flows != nil {
981 for _, flow := range flows.ToAdd.Items {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400982 log.Debug("Adding flow", log.Fields{"deviceId": device.Id, "flowToAdd": flow})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400983 dh.flowMgr.AddFlow(flow, flowMetadata)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400984 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400985 for _, flow := range flows.ToRemove.Items {
986 log.Debug("Removing flow", log.Fields{"deviceId": device.Id, "flowToRemove": flow})
987 dh.flowMgr.RemoveFlow(flow)
988 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400989 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700990 if groups != nil && flows != nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400991 for _, flow := range flows.ToRemove.Items {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700992 log.Debug("Removing flow", log.Fields{"deviceID": device.Id, "flowToRemove": flow})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400993 // dh.flowMgr.RemoveFlow(flow)
994 }
995 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400996 log.Debug("UpdateFlowsIncrementally done successfully")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400997 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530998}
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400999
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001000//DisableDevice disables the given device
1001//It marks the following for the given device:
1002//Device-Handler Admin-State : down
1003//Device Port-State: UNKNOWN
1004//Device Oper-State: UNKNOWN
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001005func (dh *DeviceHandler) DisableDevice(device *voltha.Device) error {
Chaitrashree G S44124192019-08-07 20:21:36 -04001006 /* On device disable ,admin state update has to be done prior sending request to agent since
1007 the indication thread may processes invalid indications of ONU and OLT*/
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001008 dh.lockDevice.Lock()
1009 dh.adminState = "down"
1010 dh.lockDevice.Unlock()
Chaitrashree G S44124192019-08-07 20:21:36 -04001011 if _, err := dh.Client.DisableOlt(context.Background(), new(oop.Empty)); err != nil {
1012 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
1013 dh.lockDevice.Lock()
1014 dh.adminState = "up"
1015 dh.lockDevice.Unlock()
1016 return err
1017 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001018 log.Debug("olt-disabled")
Chaitrashree G S44124192019-08-07 20:21:36 -04001019 dh.lockDevice.Lock()
1020 /* Discovered ONUs entries need to be cleared , since on device disable the child devices goes to
1021 UNREACHABLE state which needs to be configured again*/
1022 dh.discOnus = make(map[string]bool)
1023 dh.lockDevice.Unlock()
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001024
1025 cloned := proto.Clone(device).(*voltha.Device)
1026 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001027 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); err != nil {
1028 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001029 return err
1030 }
1031
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001032 log.Debugw("Disable_device-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001033 return nil
1034}
1035
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001036//ReenableDevice re-enables the olt device after disable
1037//It marks the following for the given device:
1038//Device-Handler Admin-State : up
1039//Device Port-State: ACTIVE
1040//Device Oper-State: ACTIVE
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001041func (dh *DeviceHandler) ReenableDevice(device *voltha.Device) error {
1042 if _, err := dh.Client.ReenableOlt(context.Background(), new(oop.Empty)); err != nil {
1043 log.Errorw("Failed to reenable olt ", log.Fields{"err": err})
1044 return err
1045 }
1046
1047 dh.lockDevice.Lock()
1048 dh.adminState = "up"
1049 dh.lockDevice.Unlock()
1050 log.Debug("olt-reenabled")
1051
1052 cloned := proto.Clone(device).(*voltha.Device)
1053 // Update the all ports state on that device to enable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001054 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
1055 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001056 return err
1057 }
1058
1059 //Update the device oper status as ACTIVE
1060 cloned.OperStatus = voltha.OperStatus_ACTIVE
1061 dh.device = cloned
1062
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001063 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1064 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001065 return err
1066 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001067 log.Debugw("ReEnableDevice-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001068
1069 return nil
1070}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001071
Devmalya Pauleb2e9552019-08-27 19:42:00 -04001072func (dh *DeviceHandler) clearUNIData(onu *OnuDevice, uniPorts []*voltha.Port) error {
1073 var uniID uint32
1074 var err error
1075 for _, port := range uniPorts {
1076 if port.Type == voltha.Port_ETHERNET_UNI {
1077 uniID = UniIDFromPortNum(port.PortNo)
1078 /* Delete tech-profile instance from the KV store */
1079 if err = dh.flowMgr.DeleteTechProfileInstance(onu.intfID, onu.onuID, uniID, onu.serialNumber); err != nil {
1080 log.Debugw("Failed-to-remove-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
1081 }
1082 log.Debugw("Deleted-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
1083 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(onu.intfID, onu.onuID, uniID)
1084 for _, flowID := range flowIDs {
1085 dh.resourceMgr.FreeFlowID(onu.intfID, int32(onu.onuID), int32(uniID), flowID)
1086 }
1087 dh.resourceMgr.FreePONResourcesForONU(onu.intfID, onu.onuID, uniID)
1088 if err = dh.resourceMgr.RemoveTechProfileIDForOnu(onu.intfID, onu.onuID, uniID); err != nil {
1089 log.Debugw("Failed-to-remove-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1090 }
1091 log.Debugw("Removed-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1092 if err = dh.resourceMgr.RemoveMeterIDForOnu("upstream", onu.intfID, onu.onuID, uniID); err != nil {
1093 log.Debugw("Failed-to-remove-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1094 }
1095 log.Debugw("Removed-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1096 if err = dh.resourceMgr.RemoveMeterIDForOnu("downstream", onu.intfID, onu.onuID, uniID); err != nil {
1097 log.Debugw("Failed-to-remove-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
1098 }
1099 log.Debugw("Removed-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
1100 }
1101 }
1102 return nil
1103}
1104
1105func (dh *DeviceHandler) clearNNIData() error {
1106 nniUniID := -1
1107 nniOnuID := -1
1108 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1109 log.Debugw("Current flow ids for nni", log.Fields{"flow-ids": flowIDs})
1110 for _, flowID := range flowIDs {
1111 dh.resourceMgr.FreeFlowID(uint32(dh.nniIntfID), -1, -1, uint32(flowID))
1112 }
1113 //Free the flow-ids for the NNI port
1114 dh.resourceMgr.FreePONResourcesForONU(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1115 /* Free ONU IDs for each pon port
1116 intfIDToONUIds is a map of intf-id: [onu-ids]*/
1117 intfIDToONUIds := make(map[uint32][]uint32)
1118 for _, onu := range dh.onus {
1119 intfIDToONUIds[onu.intfID] = append(intfIDToONUIds[onu.intfID], onu.onuID)
1120 }
1121 for intfID, onuIds := range intfIDToONUIds {
1122 dh.resourceMgr.FreeonuID(intfID, onuIds)
1123 }
1124 return nil
1125}
1126
1127// DeleteDevice deletes the device instance from openolt handler array. Also clears allocated resource manager resources. Also reboots the OLT hardware!
1128func (dh *DeviceHandler) DeleteDevice(device *voltha.Device) error {
1129 log.Debug("Function entry delete device")
1130 dh.lockDevice.Lock()
1131 dh.adminState = "deleted"
1132 dh.lockDevice.Unlock()
1133 /* Clear the KV store data associated with the all the UNI ports
1134 This clears up flow data and also resource map data for various
1135 other pon resources like alloc_id and gemport_id
1136 */
1137 for _, onu := range dh.onus {
1138 childDevice, err := dh.coreProxy.GetDevice(nil, dh.deviceID, onu.deviceID)
1139 if err != nil {
1140 log.Debug("Failed to get onu device")
1141 continue
1142 }
1143 uniPorts := childDevice.Ports
1144 log.Debugw("onu-uni-ports", log.Fields{"onu-ports": uniPorts})
1145 if err := dh.clearUNIData(onu, uniPorts); err != nil {
1146 log.Debugw("Failed to clear data for onu", log.Fields{"onu-device": onu})
1147 }
1148 }
1149 /* Clear the flows from KV store associated with NNI port.
1150 There are mostly trap rules from NNI port (like LLDP)
1151 */
1152 if err := dh.clearNNIData(); err != nil {
1153 log.Debugw("Failed to clear data for NNI port", log.Fields{"device-id": dh.deviceID})
1154 }
1155 /* Clear the resource pool for each PON port*/
1156 if err := dh.resourceMgr.Delete(); err != nil {
1157 log.Debug("Failed-to-remove-device-from-Resource-mananger-KV-store")
1158 }
1159 /*Delete ONU map for the device*/
1160 for onu := range dh.onus {
1161 delete(dh.onus, onu)
1162 }
1163 log.Debug("Removed-device-from-Resource-manager-KV-store")
1164 //Reset the state
1165 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1166 log.Errorw("Failed-to-reboot-olt ", log.Fields{"err": err})
1167 return err
1168 }
1169 cloned := proto.Clone(device).(*voltha.Device)
1170 cloned.OperStatus = voltha.OperStatus_UNKNOWN
1171 cloned.ConnectStatus = voltha.ConnectStatus_UNREACHABLE
1172 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1173 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
1174 return err
1175 }
1176 return nil
1177}
1178
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001179//RebootDevice reboots the given device
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001180func (dh *DeviceHandler) RebootDevice(device *voltha.Device) error {
1181 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1182 log.Errorw("Failed to reboot olt ", log.Fields{"err": err})
1183 return err
1184 }
1185
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001186 log.Debugw("rebooted-device-successfully", log.Fields{"deviceID": device.Id})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001187
1188 return nil
1189}
1190
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001191func (dh *DeviceHandler) handlePacketIndication(packetIn *oop.PacketIndication) {
1192 log.Debugw("Received packet-in", log.Fields{"packet-indication": *packetIn})
1193 logicalPortNum, err := dh.flowMgr.GetLogicalPortFromPacketIn(packetIn)
1194 if err != nil {
1195 log.Errorw("Error getting logical port from packet-in", log.Fields{"error": err})
1196 return
1197 }
1198 log.Debugw("sending packet-in to core", log.Fields{"logicalPortNum": logicalPortNum, "packet": *packetIn})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001199 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPortNum, packetIn.Pkt); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001200 log.Errorw("Error sending packet-in to core", log.Fields{"error": err})
1201 return
1202 }
1203 log.Debug("Success sending packet-in to core!")
1204}
1205
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001206// PacketOut sends packet-out from VOLTHA to OLT on the egress port provided
1207func (dh *DeviceHandler) PacketOut(egressPortNo int, packet *of.OfpPacketOut) error {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001208 log.Debugw("incoming-packet-out", log.Fields{"deviceID": dh.deviceID, "egress_port_no": egressPortNo,
1209 "pkt-length": len(packet.Data), "packetData": hex.EncodeToString(packet.Data)})
1210
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001211 egressPortType := IntfIDToPortTypeName(uint32(egressPortNo))
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001212 if egressPortType == voltha.Port_ETHERNET_UNI {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001213 outerEthType := (uint16(packet.Data[12]) << 8) | uint16(packet.Data[13])
1214 innerEthType := (uint16(packet.Data[16]) << 8) | uint16(packet.Data[17])
1215 if outerEthType == 0x88a8 || outerEthType == 0x8100 {
1216 if innerEthType == 0x8100 {
1217 // q-in-q 802.1ad or 802.1q double tagged packet.
1218 // slice out the outer tag.
1219 packet.Data = append(packet.Data[:12], packet.Data[16:]...)
1220 log.Debugw("packet-now-single-tagged", log.Fields{"packetData": hex.EncodeToString(packet.Data)})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001221 }
1222 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001223 intfID := IntfIDFromUniPortNum(uint32(egressPortNo))
1224 onuID := OnuIDFromPortNum(uint32(egressPortNo))
Manikkaraj kb1d51442019-07-23 10:41:02 -04001225 uniID := UniIDFromPortNum(uint32(egressPortNo))
1226
1227 gemPortID, err := dh.flowMgr.GetPacketOutGemPortID(intfID, onuID, uint32(egressPortNo))
1228 if err != nil {
1229 // In this case the openolt agent will receive the gemPortID as 0.
1230 // The agent tries to retrieve the gemPortID in this case.
1231 // This may not always succeed at the agent and packetOut may fail.
1232 log.Error("failed-to-retrieve-gemport-id-for-packet-out")
1233 }
1234
1235 onuPkt := oop.OnuPacket{IntfId: intfID, OnuId: onuID, PortNo: uint32(egressPortNo), GemportId: gemPortID, Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001236
1237 log.Debugw("sending-packet-to-onu", log.Fields{"egress_port_no": egressPortNo, "IntfId": intfID, "onuID": onuID,
Manikkaraj kb1d51442019-07-23 10:41:02 -04001238 "uniID": uniID, "gemPortID": gemPortID, "packet": hex.EncodeToString(packet.Data)})
Matt Jeanneret1359c732019-08-01 21:40:02 -04001239
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001240 if _, err := dh.Client.OnuPacketOut(context.Background(), &onuPkt); err != nil {
1241 log.Errorw("Error while sending packet-out to ONU", log.Fields{"error": err})
1242 return err
1243 }
1244 } else if egressPortType == voltha.Port_ETHERNET_NNI {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001245 uplinkPkt := oop.UplinkPacket{IntfId: IntfIDFromNniPortNum(uint32(egressPortNo)), Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001246
1247 log.Debugw("sending-packet-to-nni", log.Fields{"uplink_pkt": uplinkPkt, "packet": hex.EncodeToString(packet.Data)})
1248
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001249 if _, err := dh.Client.UplinkPacketOut(context.Background(), &uplinkPkt); err != nil {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001250 log.Errorw("Error while sending packet-out to NNI", log.Fields{"error": err})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001251 return err
1252 }
1253 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001254 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 -04001255 }
1256 return nil
1257}
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001258
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001259func (dh *DeviceHandler) formOnuKey(intfID, onuID uint32) string {
1260 return "" + strconv.Itoa(int(intfID)) + "." + strconv.Itoa(int(onuID))
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001261}