blob: 9ad9941f62f9da45b8e9e2695d76ecb8534047d4 [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 {
serkant.uluderya245caba2019-09-24 23:15:29 -0700385 dh.lockDevice.Lock()
386 defer dh.lockDevice.Unlock()
Girish Gowdrud4245152019-05-10 00:47:31 -0400387 log.Debug("do-state-down-start")
388
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700389 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400390 if err != nil || device == nil {
391 /*TODO: needs to handle error scenarios */
392 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700393 return errors.New("failed to fetch device device")
Girish Gowdrud4245152019-05-10 00:47:31 -0400394 }
395
396 cloned := proto.Clone(device).(*voltha.Device)
397 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700398 if er := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); er != nil {
399 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": er})
400 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400401 }
402
403 //Update the device oper state and connection status
404 cloned.OperStatus = voltha.OperStatus_UNKNOWN
405 cloned.ConnectStatus = common.ConnectStatus_UNREACHABLE
406 dh.device = cloned
407
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700408 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
409 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": er})
410 return er
Girish Gowdrud4245152019-05-10 00:47:31 -0400411 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400412
413 //get the child device for the parent device
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700414 onuDevices, err := dh.coreProxy.GetChildDevices(context.TODO(), dh.device.Id)
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400415 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700416 log.Errorw("failed to get child devices information", log.Fields{"deviceID": dh.device.Id, "error": err})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400417 return err
418 }
419 for _, onuDevice := range onuDevices.Items {
420
421 // Update onu state as down in onu adapter
422 onuInd := oop.OnuIndication{}
423 onuInd.OperState = "down"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700424 er := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), &onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
425 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
426 if er != nil {
427 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
428 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
serkant.uluderya245caba2019-09-24 23:15:29 -0700429 //Do not return here and continue to process other ONUs
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700430 }
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400431 }
serkant.uluderya245caba2019-09-24 23:15:29 -0700432 /* Discovered ONUs entries need to be cleared , since after OLT
433 is up, it starts sending discovery indications again*/
434 dh.discOnus = make(map[string]bool)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700435 log.Debugw("do-state-down-end", log.Fields{"deviceID": device.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700436 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530437}
438
439// doStateInit dial the grpc before going to init state
440func (dh *DeviceHandler) doStateInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400441 var err error
Girish Gowdrud4245152019-05-10 00:47:31 -0400442 dh.clientCon, err = grpc.Dial(dh.device.GetHostAndPort(), grpc.WithInsecure(), grpc.WithBlock())
Girish Gowdru0c588b22019-04-23 23:24:56 -0400443 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700444 log.Errorw("Failed to dial device", log.Fields{"DeviceId": dh.deviceID, "HostAndPort": dh.device.GetHostAndPort(), "err": err})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400445 return err
446 }
447 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530448}
449
450// postInit create olt client instance to invoke RPC on the olt device
451func (dh *DeviceHandler) postInit() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400452 dh.Client = oop.NewOpenoltClient(dh.clientCon)
453 dh.transitionMap.Handle(GrpcConnected)
454 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530455}
456
457// doStateConnected get the device info and update to voltha core
458func (dh *DeviceHandler) doStateConnected() error {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400459 log.Debug("OLT device has been connected")
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400460
461 // Case where OLT is disabled and then rebooted.
462 if dh.adminState == "down" {
463 log.Debugln("do-state-connected--device-admin-state-down")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700464 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400465 if err != nil || device == nil {
466 /*TODO: needs to handle error scenarios */
467 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
468 }
469
470 cloned := proto.Clone(device).(*voltha.Device)
471 cloned.ConnectStatus = voltha.ConnectStatus_REACHABLE
472 cloned.OperStatus = voltha.OperStatus_UNKNOWN
473 dh.device = cloned
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700474 if er := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); er != nil {
475 log.Errorw("error-updating-device-state", log.Fields{"deviceID": dh.device.Id, "error": er})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -0400476 }
477
Chaitrashree G S44124192019-08-07 20:21:36 -0400478 // 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 -0400479 _, err = dh.Client.DisableOlt(context.Background(), new(oop.Empty))
480 if err != nil {
481 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
482 }
483
484 // Start reading indications
485 go dh.readIndications()
486 return nil
487 }
488
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400489 deviceInfo, err := dh.populateDeviceInfo()
cuilin20187b2a8c32019-03-26 19:52:28 -0700490 if err != nil {
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400491 log.Errorw("Unable to populate Device Info", log.Fields{"err": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700492 return err
493 }
Girish Gowdrud4245152019-05-10 00:47:31 -0400494
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700495 device, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, dh.device.Id)
Girish Gowdrud4245152019-05-10 00:47:31 -0400496 if err != nil || device == nil {
497 /*TODO: needs to handle error scenarios */
498 log.Errorw("Failed to fetch device device", log.Fields{"err": err})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700499 return err
Girish Gowdrud4245152019-05-10 00:47:31 -0400500 }
501 cloned := proto.Clone(device).(*voltha.Device)
502 // Update the all ports (if available) on that device to ACTIVE.
503 // The ports do not normally exist, unless the device is coming back from a reboot
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700504 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
505 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdrud4245152019-05-10 00:47:31 -0400506 return err
507 }
508
Girish Gowdru0c588b22019-04-23 23:24:56 -0400509 KVStoreHostPort := fmt.Sprintf("%s:%d", dh.openOLT.KVStoreHost, dh.openOLT.KVStorePort)
510 // Instantiate resource manager
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700511 if dh.resourceMgr = rsrcMgr.NewResourceMgr(dh.deviceID, KVStoreHostPort, dh.openOLT.KVStoreType, dh.deviceType, deviceInfo); dh.resourceMgr == nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400512 log.Error("Error while instantiating resource manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700513 return errors.New("instantiating resource manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400514 }
515 // Instantiate flow manager
516 if dh.flowMgr = NewFlowManager(dh, dh.resourceMgr); dh.flowMgr == nil {
517 log.Error("Error while instantiating flow manager")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700518 return errors.New("instantiating flow manager failed")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400519 }
520 /* TODO: Instantiate Alarm , stats , BW managers */
Devmalya Paulfb990a52019-07-09 10:01:49 -0400521 /* Instantiating Event Manager to handle Alarms and KPIs */
Devmalya Paul90ca3012019-09-02 21:55:45 -0400522 dh.eventMgr = NewEventMgr(dh.EventProxy, dh)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530523
cuilin20187b2a8c32019-03-26 19:52:28 -0700524 // Start reading indications
525 go dh.readIndications()
526 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530527}
528
Matt Jeanneretf4fdcd72019-07-19 20:03:23 -0400529func (dh *DeviceHandler) populateDeviceInfo() (*oop.DeviceInfo, error) {
530 var err error
531 var deviceInfo *oop.DeviceInfo
532
533 deviceInfo, err = dh.Client.GetDeviceInfo(context.Background(), new(oop.Empty))
534
535 if err != nil {
536 log.Errorw("Failed to fetch device info", log.Fields{"err": err})
537 return nil, err
538 }
539 if deviceInfo == nil {
540 log.Errorw("Device info is nil", log.Fields{})
541 return nil, errors.New("failed to get device info from OLT")
542 }
543
544 log.Debugw("Fetched device info", log.Fields{"deviceInfo": deviceInfo})
545 dh.device.Root = true
546 dh.device.Vendor = deviceInfo.Vendor
547 dh.device.Model = deviceInfo.Model
548 dh.device.SerialNumber = deviceInfo.DeviceSerialNumber
549 dh.device.HardwareVersion = deviceInfo.HardwareVersion
550 dh.device.FirmwareVersion = deviceInfo.FirmwareVersion
551
552 if deviceInfo.DeviceId == "" {
553 log.Warnw("no-device-id-provided-using-host", log.Fields{"hostport": dh.device.GetHostAndPort()})
554 host := strings.Split(dh.device.GetHostAndPort(), ":")[0]
555 genmac, err := generateMacFromHost(host)
556 if err != nil {
557 return nil, err
558 }
559 log.Debugw("using-host-for-mac-address", log.Fields{"host": host, "mac": genmac})
560 dh.device.MacAddress = genmac
561 } else {
562 dh.device.MacAddress = deviceInfo.DeviceId
563 }
564
565 // Synchronous call to update device - this method is run in its own go routine
566 if err := dh.coreProxy.DeviceUpdate(context.TODO(), dh.device); err != nil {
567 log.Errorw("error-updating-device", log.Fields{"deviceID": dh.device.Id, "error": err})
568 return nil, err
569 }
570
571 return deviceInfo, nil
572}
573
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700574//AdoptDevice adopts the OLT device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530575func (dh *DeviceHandler) AdoptDevice(device *voltha.Device) {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400576 dh.transitionMap = NewTransitionMap(dh)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700577 log.Infow("Adopt_device", log.Fields{"deviceID": device.Id, "Address": device.GetHostAndPort()})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400578 dh.transitionMap.Handle(DeviceInit)
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530579}
580
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700581//GetOfpDeviceInfo Gets the Ofp information of the given device
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530582func (dh *DeviceHandler) GetOfpDeviceInfo(device *voltha.Device) (*ic.SwitchCapability, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700583 return &ic.SwitchCapability{
584 Desc: &of.OfpDesc{
Devmalya Paul70dd4972019-06-10 15:19:17 +0530585 MfrDesc: "VOLTHA Project",
cuilin20187b2a8c32019-03-26 19:52:28 -0700586 HwDesc: "open_pon",
587 SwDesc: "open_pon",
588 SerialNum: dh.device.SerialNumber,
589 },
590 SwitchFeatures: &of.OfpSwitchFeatures{
591 NBuffers: 256,
592 NTables: 2,
593 Capabilities: uint32(of.OfpCapabilities_OFPC_FLOW_STATS |
594 of.OfpCapabilities_OFPC_TABLE_STATS |
595 of.OfpCapabilities_OFPC_PORT_STATS |
596 of.OfpCapabilities_OFPC_GROUP_STATS),
597 },
598 }, nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530599}
600
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700601//GetOfpPortInfo Get Ofp port information
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530602func (dh *DeviceHandler) GetOfpPortInfo(device *voltha.Device, portNo int64) (*ic.PortCapability, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700603 capacity := uint32(of.OfpPortFeatures_OFPPF_1GB_FD | of.OfpPortFeatures_OFPPF_FIBER)
cuilin20187b2a8c32019-03-26 19:52:28 -0700604 return &ic.PortCapability{
605 Port: &voltha.LogicalPort{
606 OfpPort: &of.OfpPort{
607 HwAddr: macAddressToUint32Array(dh.device.MacAddress),
608 Config: 0,
609 State: uint32(of.OfpPortState_OFPPS_LIVE),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700610 Curr: capacity,
611 Advertised: capacity,
612 Peer: capacity,
cuilin20187b2a8c32019-03-26 19:52:28 -0700613 CurrSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
614 MaxSpeed: uint32(of.OfpPortFeatures_OFPPF_1GB_FD),
615 },
616 DeviceId: dh.device.Id,
617 DevicePortNo: uint32(portNo),
618 },
619 }, nil
620}
621
William Kurkianff524662019-08-20 10:34:30 -0400622func (dh *DeviceHandler) omciIndication(omciInd *oop.OmciIndication) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700623 log.Debugw("omci indication", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700624 var deviceType string
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700625 var deviceID string
626 var proxyDeviceID string
cuilin20187b2a8c32019-03-26 19:52:28 -0700627
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700628 onuKey := dh.formOnuKey(omciInd.IntfId, omciInd.OnuId)
629 if onuInCache, ok := dh.onus[onuKey]; !ok {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700630 log.Debugw("omci indication for a device not in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
631 ponPort := IntfIDToPortNo(omciInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700632 kwargs := make(map[string]interface{})
633 kwargs["onu_id"] = omciInd.OnuId
634 kwargs["parent_port_no"] = ponPort
cuilin20187b2a8c32019-03-26 19:52:28 -0700635
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700636 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
637 if err != nil {
William Kurkianff524662019-08-20 10:34:30 -0400638 log.Errorw("onu not found", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId, "error": err})
639 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700640 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700641 deviceType = onuDevice.Type
642 deviceID = onuDevice.Id
643 proxyDeviceID = onuDevice.ProxyAddress.DeviceId
644 //if not exist in cache, then add to cache.
645 dh.onus[onuKey] = NewOnuDevice(deviceID, deviceType, onuDevice.SerialNumber, omciInd.OnuId, omciInd.IntfId, proxyDeviceID)
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700646 } else {
647 //found in cache
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700648 log.Debugw("omci indication for a device in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700649 deviceType = onuInCache.deviceType
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700650 deviceID = onuInCache.deviceID
651 proxyDeviceID = onuInCache.proxyDeviceID
cuilin20187b2a8c32019-03-26 19:52:28 -0700652 }
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700653
654 omciMsg := &ic.InterAdapterOmciMessage{Message: omciInd.Pkt}
655 if sendErr := dh.AdapterProxy.SendInterAdapterMessage(context.Background(), omciMsg,
656 ic.InterAdapterMessageType_OMCI_REQUEST, dh.deviceType, deviceType,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700657 deviceID, proxyDeviceID, ""); sendErr != nil {
William Kurkianff524662019-08-20 10:34:30 -0400658 log.Errorw("send omci request error", log.Fields{"fromAdapter": dh.deviceType, "toAdapter": deviceType, "onuID": deviceID, "proxyDeviceID": proxyDeviceID, "error": sendErr})
659 return
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700660 }
William Kurkianff524662019-08-20 10:34:30 -0400661 return
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530662}
663
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700664//ProcessInterAdapterMessage sends the proxied messages to the target device
665// If the proxy address is not found in the unmarshalled message, it first fetches the onu device for which the message
666// is meant, and then send the unmarshalled omci message to this onu
667func (dh *DeviceHandler) ProcessInterAdapterMessage(msg *ic.InterAdapterMessage) error {
668 log.Debugw("Process_inter_adapter_message", log.Fields{"msgID": msg.Header.Id})
cuilin20187b2a8c32019-03-26 19:52:28 -0700669 if msg.Header.Type == ic.InterAdapterMessageType_OMCI_REQUEST {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700670 msgID := msg.Header.Id
cuilin20187b2a8c32019-03-26 19:52:28 -0700671 fromTopic := msg.Header.FromTopic
672 toTopic := msg.Header.ToTopic
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700673 toDeviceID := msg.Header.ToDeviceId
674 proxyDeviceID := msg.Header.ProxyDeviceId
cuilin20187b2a8c32019-03-26 19:52:28 -0700675
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700676 log.Debugw("omci request message header", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700677
678 msgBody := msg.GetBody()
679
680 omciMsg := &ic.InterAdapterOmciMessage{}
681 if err := ptypes.UnmarshalAny(msgBody, omciMsg); err != nil {
682 log.Warnw("cannot-unmarshal-omci-msg-body", log.Fields{"error": err})
683 return err
684 }
685
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700686 if omciMsg.GetProxyAddress() == nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700687 onuDevice, err := dh.coreProxy.GetDevice(context.TODO(), dh.device.Id, toDeviceID)
688 if err != nil {
689 log.Errorw("onu not found", log.Fields{"onuDeviceId": toDeviceID, "error": err})
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700690 return err
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700691 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700692 log.Debugw("device retrieved from core", log.Fields{"msgID": msgID, "fromTopic": fromTopic, "toTopic": toTopic, "toDeviceID": toDeviceID, "proxyDeviceID": proxyDeviceID})
693 dh.sendProxiedMessage(onuDevice, omciMsg)
694
cuilin20187b2a8c32019-03-26 19:52:28 -0700695 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700696 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 -0700697 dh.sendProxiedMessage(nil, omciMsg)
cuilin20187b2a8c32019-03-26 19:52:28 -0700698 }
699
700 } else {
701 log.Errorw("inter-adapter-unhandled-type", log.Fields{"msgType": msg.Header.Type})
702 }
703 return nil
Phaneendra Manda4c62c802019-03-06 21:37:49 +0530704}
705
cuilin20187b2a8c32019-03-26 19:52:28 -0700706func (dh *DeviceHandler) sendProxiedMessage(onuDevice *voltha.Device, omciMsg *ic.InterAdapterOmciMessage) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700707 var intfID uint32
708 var onuID uint32
709 var connectStatus common.ConnectStatus_ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700710 if onuDevice != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700711 intfID = onuDevice.ProxyAddress.GetChannelId()
712 onuID = onuDevice.ProxyAddress.GetOnuId()
713 connectStatus = onuDevice.ConnectStatus
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700714 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700715 intfID = omciMsg.GetProxyAddress().GetChannelId()
716 onuID = omciMsg.GetProxyAddress().GetOnuId()
717 connectStatus = omciMsg.GetConnectStatus()
Mahir Gunyela3f9add2019-06-06 15:13:19 -0700718 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700719 if connectStatus != voltha.ConnectStatus_REACHABLE {
720 log.Debugw("ONU is not reachable, cannot send OMCI", log.Fields{"intfID": intfID, "onuID": onuID})
cuilin20187b2a8c32019-03-26 19:52:28 -0700721 return
722 }
723
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700724 omciMessage := &oop.OmciMsg{IntfId: intfID, OnuId: onuID, Pkt: omciMsg.Message}
cuilin20187b2a8c32019-03-26 19:52:28 -0700725
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700726 _, err := dh.Client.OmciMsgOut(context.Background(), omciMessage)
727 if err != nil {
728 log.Errorw("unable to send omci-msg-out", log.Fields{"IntfID": intfID, "OnuID": onuID, "Msg": omciMessage})
729 return
730 }
731 log.Debugw("omci-message-sent", log.Fields{"intfID": intfID, "onuID": onuID, "omciMsg": string(omciMsg.GetMessage())})
cuilin20187b2a8c32019-03-26 19:52:28 -0700732}
733
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700734func (dh *DeviceHandler) activateONU(intfID uint32, onuID int64, serialNum *oop.SerialNumber, serialNumber string) {
735 log.Debugw("activate-onu", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum, "serialNumber": serialNumber})
736 dh.flowMgr.UpdateOnuInfo(intfID, uint32(onuID), serialNumber)
cuilin20187b2a8c32019-03-26 19:52:28 -0700737 // TODO: need resource manager
738 var pir uint32 = 1000000
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700739 Onu := oop.Onu{IntfId: intfID, OnuId: uint32(onuID), SerialNumber: serialNum, Pir: pir}
manikkaraj kbf256be2019-03-25 00:13:48 +0530740 if _, err := dh.Client.ActivateOnu(context.Background(), &Onu); err != nil {
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400741 st, _ := status.FromError(err)
742 if st.Code() == codes.AlreadyExists {
743 log.Debug("ONU activation is in progress", log.Fields{"SerialNumber": serialNumber})
744 } else {
745 log.Errorw("activate-onu-failed", log.Fields{"Onu": Onu, "err ": err})
746 }
cuilin20187b2a8c32019-03-26 19:52:28 -0700747 } else {
748 log.Infow("activated-onu", log.Fields{"SerialNumber": serialNumber})
749 }
750}
751
Matt Jeanneret53539512019-07-20 14:47:02 -0400752func (dh *DeviceHandler) onuDiscIndication(onuDiscInd *oop.OnuDiscIndication, sn string) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700753 channelID := onuDiscInd.GetIntfId()
754 parentPortNo := IntfIDToPortNo(onuDiscInd.GetIntfId(), voltha.Port_PON_OLT)
Matt Jeanneret53539512019-07-20 14:47:02 -0400755
756 log.Debugw("new-discovery-indication", log.Fields{"sn": sn})
757 dh.lockDevice.Lock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400758 if _, ok := dh.discOnus[sn]; ok {
Matt Jeanneret53539512019-07-20 14:47:02 -0400759 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400760 log.Debugw("onu-sn-is-already-being-processed", log.Fields{"sn": sn})
Matt Jeanneret53539512019-07-20 14:47:02 -0400761 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700762 }
763
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400764 dh.discOnus[sn] = true
Matt Jeanneret53539512019-07-20 14:47:02 -0400765 log.Debugw("new-discovery-indications-list", log.Fields{"discOnus": dh.discOnus})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400766 dh.lockDevice.Unlock()
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400767
cuilin20187b2a8c32019-03-26 19:52:28 -0700768 kwargs := make(map[string]interface{})
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400769 if sn != "" {
770 kwargs["serial_number"] = sn
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400771 } else {
Matt Jeanneret53539512019-07-20 14:47:02 -0400772 log.Errorw("invalid onu serial number", log.Fields{"sn": sn})
773 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400774 }
775
776 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
777 var onuID uint32
778 if onuDevice == nil || err != nil {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700779 //This is the first time ONU discovered. Create an OnuID for it.
Matt Jeanneret53539512019-07-20 14:47:02 -0400780 ponintfid := onuDiscInd.GetIntfId()
781 dh.lockDevice.Lock()
782 onuID, err = dh.resourceMgr.GetONUID(ponintfid)
783 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400784 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400785 log.Errorw("failed to fetch onuID from resource manager", log.Fields{"pon-intf-id": ponintfid, "err": err})
786 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400787 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700788 if onuDevice, err = dh.coreProxy.ChildDeviceDetected(context.TODO(), dh.device.Id, int(parentPortNo),
Chaitrashree G See824a22019-07-28 18:28:27 -0400789 "", int(channelID),
Mahir Gunyele77977b2019-06-27 05:36:22 -0700790 string(onuDiscInd.SerialNumber.GetVendorId()), sn, int64(onuID)); onuDevice == nil {
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400791 log.Errorw("Create onu error",
792 log.Fields{"parent_id": dh.device.Id, "ponPort": onuDiscInd.GetIntfId(),
793 "onuID": onuID, "sn": sn, "error": err})
Matt Jeanneret53539512019-07-20 14:47:02 -0400794 return
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400795 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400796 log.Debugw("onu-child-device-added", log.Fields{"onuDevice": onuDevice})
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400797
798 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700799 //ONU already discovered before. Use the same OnuID.
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400800 onuID = onuDevice.ProxyAddress.OnuId
Chaitrashree G Sbe6ab942019-05-24 06:42:49 -0400801 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700802 //Insert the ONU into cache to use in OnuIndication.
803 //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 -0700804 log.Debugw("ONU discovery indication key create", log.Fields{"onuID": onuID,
805 "intfId": onuDiscInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700806 onuKey := dh.formOnuKey(onuDiscInd.GetIntfId(), onuID)
Matt Jeanneret53539512019-07-20 14:47:02 -0400807
808 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700809 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuID, onuDiscInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400810 log.Debugw("new-onu-device-discovered", log.Fields{"onu": dh.onus[onuKey]})
811 dh.lockDevice.Unlock()
Chaitrashree G S35b5d802019-07-08 23:12:03 -0400812
Mahir Gunyele77977b2019-06-27 05:36:22 -0700813 err = dh.coreProxy.DeviceStateUpdate(context.TODO(), onuDevice.Id, common.ConnectStatus_REACHABLE, common.OperStatus_DISCOVERED)
814 if err != nil {
Matt Jeanneret53539512019-07-20 14:47:02 -0400815 log.Errorw("failed to update device state", log.Fields{"DeviceID": onuDevice.Id, "err": err})
816 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700817 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700818 log.Debugw("onu-discovered-reachable", log.Fields{"deviceId": onuDevice.Id})
819 //TODO: We put this sleep here to prevent the race between state update and onuIndication
820 //In onuIndication the operStatus of device is checked. If it is still not updated in KV store
821 //then the initialisation fails.
822 time.Sleep(1 * time.Second)
823 dh.activateONU(onuDiscInd.IntfId, int64(onuID), onuDiscInd.SerialNumber, sn)
Matt Jeanneret53539512019-07-20 14:47:02 -0400824 return
cuilin20187b2a8c32019-03-26 19:52:28 -0700825}
826
827func (dh *DeviceHandler) onuIndication(onuInd *oop.OnuIndication) {
828 serialNumber := dh.stringifySerialNumber(onuInd.SerialNumber)
829
830 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700831 ponPort := IntfIDToPortNo(onuInd.GetIntfId(), voltha.Port_PON_OLT)
Mahir Gunyele77977b2019-06-27 05:36:22 -0700832 var onuDevice *voltha.Device
833 foundInCache := false
Scott Baker7eb0a932019-07-26 10:33:22 -0700834 log.Debugw("ONU indication key create", log.Fields{"onuId": onuInd.OnuId,
835 "intfId": onuInd.GetIntfId()})
Mahir Gunyele77977b2019-06-27 05:36:22 -0700836 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.OnuId)
837 if onuInCache, ok := dh.onus[onuKey]; ok {
838 //If ONU id is discovered before then use GetDevice to get onuDevice because it is cheaper.
839 foundInCache = true
840 onuDevice, _ = dh.coreProxy.GetDevice(nil, dh.device.Id, onuInCache.deviceID)
cuilin20187b2a8c32019-03-26 19:52:28 -0700841 } else {
Mahir Gunyele77977b2019-06-27 05:36:22 -0700842 //If ONU not found in adapter cache then we have to use GetChildDevice to get onuDevice
843 if serialNumber != "" {
844 kwargs["serial_number"] = serialNumber
845 } else {
846 kwargs["onu_id"] = onuInd.OnuId
847 kwargs["parent_port_no"] = ponPort
848 }
849 onuDevice, _ = dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
cuilin20187b2a8c32019-03-26 19:52:28 -0700850 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700851
852 if onuDevice != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400853 if onuDevice.ParentPortNo != ponPort {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700854 //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 -0400855 log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": onuDevice.ParentPortNo, "currentIntfId": ponPort})
cuilin20187b2a8c32019-03-26 19:52:28 -0700856 }
857
858 if onuDevice.ProxyAddress.OnuId != onuInd.OnuId {
859 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})
860 }
Mahir Gunyele77977b2019-06-27 05:36:22 -0700861 if !foundInCache {
862 onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.GetOnuId())
Matt Jeanneret53539512019-07-20 14:47:02 -0400863 dh.lockDevice.Lock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700864 dh.onus[onuKey] = NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuInd.GetOnuId(), onuInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
Matt Jeanneret53539512019-07-20 14:47:02 -0400865 dh.lockDevice.Unlock()
Mahir Gunyele77977b2019-06-27 05:36:22 -0700866 }
Scott Baker7eb0a932019-07-26 10:33:22 -0700867 dh.updateOnuStates(onuDevice, onuInd, foundInCache)
cuilin20187b2a8c32019-03-26 19:52:28 -0700868
cuilin20187b2a8c32019-03-26 19:52:28 -0700869 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700870 log.Errorw("onu not found", log.Fields{"intfID": onuInd.IntfId, "onuID": onuInd.OnuId})
cuilin20187b2a8c32019-03-26 19:52:28 -0700871 return
872 }
873
874}
875
Scott Baker7eb0a932019-07-26 10:33:22 -0700876func (dh *DeviceHandler) updateOnuStates(onuDevice *voltha.Device, onuInd *oop.OnuIndication, foundInCache bool) {
Matt Jeanneret53539512019-07-20 14:47:02 -0400877 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 -0700878 dh.updateOnuAdminState(onuInd)
879 // operState
880 if onuInd.OperState == "down" {
Matt Jeanneret53539512019-07-20 14:47:02 -0400881 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 -0700882 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
883 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
884 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
885 if err != nil {
886 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
887 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
888 }
889 } else if onuInd.OperState == "up" {
Scott Baker7eb0a932019-07-26 10:33:22 -0700890 // Ignore operstatus if device was found in cache
891 if !foundInCache && onuDevice.OperStatus != common.OperStatus_DISCOVERED {
Matt Jeanneret53539512019-07-20 14:47:02 -0400892 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 -0700893 return
894 }
Matt Jeanneret53539512019-07-20 14:47:02 -0400895 log.Debugw("sending-interadapter-onu-indication", log.Fields{"onuIndication": onuInd, "DeviceId": onuDevice.Id, "operStatus": onuDevice.OperStatus, "adminStatus": onuDevice.AdminState})
896 // TODO NEW CORE do not hardcode adapter name. Handler needs Adapter reference
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700897 err := dh.AdapterProxy.SendInterAdapterMessage(context.TODO(), onuInd, ic.InterAdapterMessageType_ONU_IND_REQUEST,
898 "openolt", onuDevice.Type, onuDevice.Id, onuDevice.ProxyAddress.DeviceId, "")
899 if err != nil {
900 log.Errorw("Failed to send inter-adapter-message", log.Fields{"OnuInd": onuInd,
901 "From Adapter": "openolt", "DevieType": onuDevice.Type, "DeviceID": onuDevice.Id})
902 return
903 }
904 } else {
905 log.Warnw("Not-implemented-or-invalid-value-of-oper-state", log.Fields{"operState": onuInd.OperState})
906 }
907}
908
909func (dh *DeviceHandler) updateOnuAdminState(onuInd *oop.OnuIndication) {
910 if onuInd.AdminState == "down" {
911 if onuInd.OperState != "down" {
912 log.Errorw("ONU-admin-state-down-and-oper-status-not-down", log.Fields{"operState": onuInd.OperState})
913 // Forcing the oper state change code to execute
914 onuInd.OperState = "down"
915 }
916 // Port and logical port update is taken care of by oper state block
917 } else if onuInd.AdminState == "up" {
918 log.Debugln("received-onu-admin-state up")
919 } else {
920 log.Errorw("Invalid-or-not-implemented-admin-state", log.Fields{"received-admin-state": onuInd.AdminState})
921 }
922 log.Debugln("admin-state-dealt-with")
923}
924
cuilin20187b2a8c32019-03-26 19:52:28 -0700925func (dh *DeviceHandler) stringifySerialNumber(serialNum *oop.SerialNumber) string {
926 if serialNum != nil {
927 return string(serialNum.VendorId) + dh.stringifyVendorSpecific(serialNum.VendorSpecific)
cuilin20187b2a8c32019-03-26 19:52:28 -0700928 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700929 return ""
cuilin20187b2a8c32019-03-26 19:52:28 -0700930}
931
932func (dh *DeviceHandler) stringifyVendorSpecific(vendorSpecific []byte) string {
933 tmp := fmt.Sprintf("%x", (uint32(vendorSpecific[0])>>4)&0x0f) +
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700934 fmt.Sprintf("%x", uint32(vendorSpecific[0]&0x0f)) +
cuilin20187b2a8c32019-03-26 19:52:28 -0700935 fmt.Sprintf("%x", (uint32(vendorSpecific[1])>>4)&0x0f) +
936 fmt.Sprintf("%x", (uint32(vendorSpecific[1]))&0x0f) +
937 fmt.Sprintf("%x", (uint32(vendorSpecific[2])>>4)&0x0f) +
938 fmt.Sprintf("%x", (uint32(vendorSpecific[2]))&0x0f) +
939 fmt.Sprintf("%x", (uint32(vendorSpecific[3])>>4)&0x0f) +
940 fmt.Sprintf("%x", (uint32(vendorSpecific[3]))&0x0f)
941 return tmp
942}
943
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700944//UpdateFlowsBulk upates the bulk flow
945func (dh *DeviceHandler) UpdateFlowsBulk() error {
946 return errors.New("unimplemented")
cuilin20187b2a8c32019-03-26 19:52:28 -0700947}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700948
949//GetChildDevice returns the child device for given parent port and onu id
950func (dh *DeviceHandler) GetChildDevice(parentPort, onuID uint32) *voltha.Device {
951 log.Debugw("GetChildDevice", log.Fields{"pon port": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400952 kwargs := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700953 kwargs["onu_id"] = onuID
Girish Gowdru0c588b22019-04-23 23:24:56 -0400954 kwargs["parent_port_no"] = parentPort
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700955 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400956 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700957 log.Errorw("onu not found", log.Fields{"intfID": parentPort, "onuID": onuID})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400958 return nil
959 }
960 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
961 return onuDevice
manikkaraj kbf256be2019-03-25 00:13:48 +0530962}
963
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700964// SendPacketInToCore sends packet-in to core
965// For this, it calls SendPacketIn of the core-proxy which uses a device specific topic to send the request.
966// The adapter handling the device creates a device specific topic
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400967func (dh *DeviceHandler) SendPacketInToCore(logicalPort uint32, packetPayload []byte) {
968 log.Debugw("SendPacketInToCore", log.Fields{"port": logicalPort, "packetPayload": packetPayload})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700969 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPort, packetPayload); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400970 log.Errorw("Error sending packetin to core", log.Fields{"error": err})
971 return
972 }
973 log.Debug("Sent packet-in to core successfully")
974}
975
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700976//UpdateFlowsIncrementally updates the device flow
Manikkaraj kb1d51442019-07-23 10:41:02 -0400977func (dh *DeviceHandler) UpdateFlowsIncrementally(device *voltha.Device, flows *of.FlowChanges, groups *of.FlowGroupChanges, flowMetadata *voltha.FlowMetadata) error {
978 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 -0400979 if flows != nil {
980 for _, flow := range flows.ToAdd.Items {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400981 log.Debug("Adding flow", log.Fields{"deviceId": device.Id, "flowToAdd": flow})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400982 dh.flowMgr.AddFlow(flow, flowMetadata)
Girish Gowdru0c588b22019-04-23 23:24:56 -0400983 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400984 for _, flow := range flows.ToRemove.Items {
985 log.Debug("Removing flow", log.Fields{"deviceId": device.Id, "flowToRemove": flow})
986 dh.flowMgr.RemoveFlow(flow)
987 }
Girish Gowdru0c588b22019-04-23 23:24:56 -0400988 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700989 if groups != nil && flows != nil {
Girish Gowdru0c588b22019-04-23 23:24:56 -0400990 for _, flow := range flows.ToRemove.Items {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700991 log.Debug("Removing flow", log.Fields{"deviceID": device.Id, "flowToRemove": flow})
Girish Gowdru0c588b22019-04-23 23:24:56 -0400992 // dh.flowMgr.RemoveFlow(flow)
993 }
994 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400995 log.Debug("UpdateFlowsIncrementally done successfully")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400996 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530997}
Girish Gowdru5ba46c92019-04-25 05:00:05 -0400998
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700999//DisableDevice disables the given device
1000//It marks the following for the given device:
1001//Device-Handler Admin-State : down
1002//Device Port-State: UNKNOWN
1003//Device Oper-State: UNKNOWN
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001004func (dh *DeviceHandler) DisableDevice(device *voltha.Device) error {
Chaitrashree G S44124192019-08-07 20:21:36 -04001005 /* On device disable ,admin state update has to be done prior sending request to agent since
1006 the indication thread may processes invalid indications of ONU and OLT*/
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001007 dh.lockDevice.Lock()
1008 dh.adminState = "down"
1009 dh.lockDevice.Unlock()
Chaitrashree G S44124192019-08-07 20:21:36 -04001010 if _, err := dh.Client.DisableOlt(context.Background(), new(oop.Empty)); err != nil {
1011 log.Errorw("Failed to disable olt ", log.Fields{"err": err})
1012 dh.lockDevice.Lock()
1013 dh.adminState = "up"
1014 dh.lockDevice.Unlock()
1015 return err
1016 }
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001017 log.Debug("olt-disabled")
Chaitrashree G S44124192019-08-07 20:21:36 -04001018 dh.lockDevice.Lock()
1019 /* Discovered ONUs entries need to be cleared , since on device disable the child devices goes to
1020 UNREACHABLE state which needs to be configured again*/
1021 dh.discOnus = make(map[string]bool)
1022 dh.lockDevice.Unlock()
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001023
1024 cloned := proto.Clone(device).(*voltha.Device)
1025 // Update the all ports state on that device to disable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001026 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_UNKNOWN); err != nil {
1027 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001028 return err
1029 }
1030
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001031 log.Debugw("Disable_device-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001032 return nil
1033}
1034
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001035//ReenableDevice re-enables the olt device after disable
1036//It marks the following for the given device:
1037//Device-Handler Admin-State : up
1038//Device Port-State: ACTIVE
1039//Device Oper-State: ACTIVE
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001040func (dh *DeviceHandler) ReenableDevice(device *voltha.Device) error {
1041 if _, err := dh.Client.ReenableOlt(context.Background(), new(oop.Empty)); err != nil {
1042 log.Errorw("Failed to reenable olt ", log.Fields{"err": err})
1043 return err
1044 }
1045
1046 dh.lockDevice.Lock()
1047 dh.adminState = "up"
1048 dh.lockDevice.Unlock()
1049 log.Debug("olt-reenabled")
1050
1051 cloned := proto.Clone(device).(*voltha.Device)
1052 // Update the all ports state on that device to enable
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001053 if err := dh.coreProxy.PortsStateUpdate(context.TODO(), cloned.Id, voltha.OperStatus_ACTIVE); err != nil {
1054 log.Errorw("updating-ports-failed", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001055 return err
1056 }
1057
1058 //Update the device oper status as ACTIVE
1059 cloned.OperStatus = voltha.OperStatus_ACTIVE
1060 dh.device = cloned
1061
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001062 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1063 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001064 return err
1065 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001066 log.Debugw("ReEnableDevice-end", log.Fields{"deviceID": device.Id})
Girish Gowdru5ba46c92019-04-25 05:00:05 -04001067
1068 return nil
1069}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001070
Devmalya Paul495b94a2019-08-27 19:42:00 -04001071func (dh *DeviceHandler) clearUNIData(onu *OnuDevice, uniPorts []*voltha.Port) error {
1072 var uniID uint32
1073 var err error
1074 for _, port := range uniPorts {
1075 if port.Type == voltha.Port_ETHERNET_UNI {
1076 uniID = UniIDFromPortNum(port.PortNo)
1077 /* Delete tech-profile instance from the KV store */
1078 if err = dh.flowMgr.DeleteTechProfileInstance(onu.intfID, onu.onuID, uniID, onu.serialNumber); err != nil {
1079 log.Debugw("Failed-to-remove-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
1080 }
1081 log.Debugw("Deleted-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
1082 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(onu.intfID, onu.onuID, uniID)
1083 for _, flowID := range flowIDs {
1084 dh.resourceMgr.FreeFlowID(onu.intfID, int32(onu.onuID), int32(uniID), flowID)
1085 }
1086 dh.resourceMgr.FreePONResourcesForONU(onu.intfID, onu.onuID, uniID)
1087 if err = dh.resourceMgr.RemoveTechProfileIDForOnu(onu.intfID, onu.onuID, uniID); err != nil {
1088 log.Debugw("Failed-to-remove-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1089 }
1090 log.Debugw("Removed-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
1091 if err = dh.resourceMgr.RemoveMeterIDForOnu("upstream", onu.intfID, onu.onuID, uniID); err != nil {
1092 log.Debugw("Failed-to-remove-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1093 }
1094 log.Debugw("Removed-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
1095 if err = dh.resourceMgr.RemoveMeterIDForOnu("downstream", onu.intfID, onu.onuID, uniID); err != nil {
1096 log.Debugw("Failed-to-remove-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
1097 }
1098 log.Debugw("Removed-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
1099 }
1100 }
1101 return nil
1102}
1103
1104func (dh *DeviceHandler) clearNNIData() error {
1105 nniUniID := -1
1106 nniOnuID := -1
1107 flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1108 log.Debugw("Current flow ids for nni", log.Fields{"flow-ids": flowIDs})
1109 for _, flowID := range flowIDs {
1110 dh.resourceMgr.FreeFlowID(uint32(dh.nniIntfID), -1, -1, uint32(flowID))
1111 }
1112 //Free the flow-ids for the NNI port
1113 dh.resourceMgr.FreePONResourcesForONU(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
1114 /* Free ONU IDs for each pon port
1115 intfIDToONUIds is a map of intf-id: [onu-ids]*/
1116 intfIDToONUIds := make(map[uint32][]uint32)
1117 for _, onu := range dh.onus {
1118 intfIDToONUIds[onu.intfID] = append(intfIDToONUIds[onu.intfID], onu.onuID)
1119 }
1120 for intfID, onuIds := range intfIDToONUIds {
1121 dh.resourceMgr.FreeonuID(intfID, onuIds)
1122 }
1123 return nil
1124}
1125
1126// DeleteDevice deletes the device instance from openolt handler array. Also clears allocated resource manager resources. Also reboots the OLT hardware!
1127func (dh *DeviceHandler) DeleteDevice(device *voltha.Device) error {
1128 log.Debug("Function entry delete device")
1129 dh.lockDevice.Lock()
1130 dh.adminState = "deleted"
1131 dh.lockDevice.Unlock()
1132 /* Clear the KV store data associated with the all the UNI ports
1133 This clears up flow data and also resource map data for various
1134 other pon resources like alloc_id and gemport_id
1135 */
1136 for _, onu := range dh.onus {
1137 childDevice, err := dh.coreProxy.GetDevice(nil, dh.deviceID, onu.deviceID)
1138 if err != nil {
1139 log.Debug("Failed to get onu device")
1140 continue
1141 }
1142 uniPorts := childDevice.Ports
1143 log.Debugw("onu-uni-ports", log.Fields{"onu-ports": uniPorts})
1144 if err := dh.clearUNIData(onu, uniPorts); err != nil {
1145 log.Debugw("Failed to clear data for onu", log.Fields{"onu-device": onu})
1146 }
1147 }
1148 /* Clear the flows from KV store associated with NNI port.
1149 There are mostly trap rules from NNI port (like LLDP)
1150 */
1151 if err := dh.clearNNIData(); err != nil {
1152 log.Debugw("Failed to clear data for NNI port", log.Fields{"device-id": dh.deviceID})
1153 }
1154 /* Clear the resource pool for each PON port*/
1155 if err := dh.resourceMgr.Delete(); err != nil {
1156 log.Debug("Failed-to-remove-device-from-Resource-mananger-KV-store")
1157 }
1158 /*Delete ONU map for the device*/
1159 for onu := range dh.onus {
1160 delete(dh.onus, onu)
1161 }
1162 log.Debug("Removed-device-from-Resource-manager-KV-store")
1163 //Reset the state
1164 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1165 log.Errorw("Failed-to-reboot-olt ", log.Fields{"err": err})
1166 return err
1167 }
1168 cloned := proto.Clone(device).(*voltha.Device)
1169 cloned.OperStatus = voltha.OperStatus_UNKNOWN
1170 cloned.ConnectStatus = voltha.ConnectStatus_UNREACHABLE
1171 if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
1172 log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
1173 return err
1174 }
1175 return nil
1176}
1177
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001178//RebootDevice reboots the given device
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001179func (dh *DeviceHandler) RebootDevice(device *voltha.Device) error {
1180 if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
1181 log.Errorw("Failed to reboot olt ", log.Fields{"err": err})
1182 return err
1183 }
1184
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001185 log.Debugw("rebooted-device-successfully", log.Fields{"deviceID": device.Id})
Girish Gowdru0fe5f7e2019-05-28 05:12:27 -04001186
1187 return nil
1188}
1189
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001190func (dh *DeviceHandler) handlePacketIndication(packetIn *oop.PacketIndication) {
1191 log.Debugw("Received packet-in", log.Fields{"packet-indication": *packetIn})
1192 logicalPortNum, err := dh.flowMgr.GetLogicalPortFromPacketIn(packetIn)
1193 if err != nil {
1194 log.Errorw("Error getting logical port from packet-in", log.Fields{"error": err})
1195 return
1196 }
1197 log.Debugw("sending packet-in to core", log.Fields{"logicalPortNum": logicalPortNum, "packet": *packetIn})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001198 if err := dh.coreProxy.SendPacketIn(context.TODO(), dh.device.Id, logicalPortNum, packetIn.Pkt); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001199 log.Errorw("Error sending packet-in to core", log.Fields{"error": err})
1200 return
1201 }
1202 log.Debug("Success sending packet-in to core!")
1203}
1204
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001205// PacketOut sends packet-out from VOLTHA to OLT on the egress port provided
1206func (dh *DeviceHandler) PacketOut(egressPortNo int, packet *of.OfpPacketOut) error {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001207 log.Debugw("incoming-packet-out", log.Fields{"deviceID": dh.deviceID, "egress_port_no": egressPortNo,
1208 "pkt-length": len(packet.Data), "packetData": hex.EncodeToString(packet.Data)})
1209
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001210 egressPortType := IntfIDToPortTypeName(uint32(egressPortNo))
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001211 if egressPortType == voltha.Port_ETHERNET_UNI {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001212 outerEthType := (uint16(packet.Data[12]) << 8) | uint16(packet.Data[13])
1213 innerEthType := (uint16(packet.Data[16]) << 8) | uint16(packet.Data[17])
1214 if outerEthType == 0x88a8 || outerEthType == 0x8100 {
1215 if innerEthType == 0x8100 {
1216 // q-in-q 802.1ad or 802.1q double tagged packet.
1217 // slice out the outer tag.
1218 packet.Data = append(packet.Data[:12], packet.Data[16:]...)
1219 log.Debugw("packet-now-single-tagged", log.Fields{"packetData": hex.EncodeToString(packet.Data)})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001220 }
1221 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001222 intfID := IntfIDFromUniPortNum(uint32(egressPortNo))
1223 onuID := OnuIDFromPortNum(uint32(egressPortNo))
Manikkaraj kb1d51442019-07-23 10:41:02 -04001224 uniID := UniIDFromPortNum(uint32(egressPortNo))
1225
1226 gemPortID, err := dh.flowMgr.GetPacketOutGemPortID(intfID, onuID, uint32(egressPortNo))
1227 if err != nil {
1228 // In this case the openolt agent will receive the gemPortID as 0.
1229 // The agent tries to retrieve the gemPortID in this case.
1230 // This may not always succeed at the agent and packetOut may fail.
1231 log.Error("failed-to-retrieve-gemport-id-for-packet-out")
1232 }
1233
1234 onuPkt := oop.OnuPacket{IntfId: intfID, OnuId: onuID, PortNo: uint32(egressPortNo), GemportId: gemPortID, Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001235
1236 log.Debugw("sending-packet-to-onu", log.Fields{"egress_port_no": egressPortNo, "IntfId": intfID, "onuID": onuID,
Manikkaraj kb1d51442019-07-23 10:41:02 -04001237 "uniID": uniID, "gemPortID": gemPortID, "packet": hex.EncodeToString(packet.Data)})
Matt Jeanneret1359c732019-08-01 21:40:02 -04001238
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001239 if _, err := dh.Client.OnuPacketOut(context.Background(), &onuPkt); err != nil {
1240 log.Errorw("Error while sending packet-out to ONU", log.Fields{"error": err})
1241 return err
1242 }
1243 } else if egressPortType == voltha.Port_ETHERNET_NNI {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001244 uplinkPkt := oop.UplinkPacket{IntfId: IntfIDFromNniPortNum(uint32(egressPortNo)), Pkt: packet.Data}
Matt Jeanneret1359c732019-08-01 21:40:02 -04001245
1246 log.Debugw("sending-packet-to-nni", log.Fields{"uplink_pkt": uplinkPkt, "packet": hex.EncodeToString(packet.Data)})
1247
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001248 if _, err := dh.Client.UplinkPacketOut(context.Background(), &uplinkPkt); err != nil {
Matt Jeanneret1359c732019-08-01 21:40:02 -04001249 log.Errorw("Error while sending packet-out to NNI", log.Fields{"error": err})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001250 return err
1251 }
1252 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001253 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 -04001254 }
1255 return nil
1256}
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001257
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001258func (dh *DeviceHandler) formOnuKey(intfID, onuID uint32) string {
1259 return "" + strconv.Itoa(int(intfID)) + "." + strconv.Itoa(int(onuID))
Mahir Gunyela3f9add2019-06-06 15:13:19 -07001260}