blob: 5d888b12d6663f1e7ba252e2fe101249916b9957 [file] [log] [blame]
Takahiro Suzuki241c10e2020-12-17 20:17:57 +09001/*
2 * Copyright 2020-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 */
16
17//Package adaptercoreonu provides the utility for onu devices, flows and statistics
18package adaptercoreonu
19
20import (
21 "context"
22 "errors"
23 "time"
24
25 "github.com/opencord/omci-lib-go"
26 me "github.com/opencord/omci-lib-go/generated"
27
28
29 "github.com/looplab/fsm"
30 "github.com/opencord/voltha-lib-go/v3/pkg/adapters/adapterif"
31 "github.com/opencord/voltha-lib-go/v3/pkg/db"
32
33 "github.com/opencord/voltha-lib-go/v3/pkg/log"
34)
35
36const (
37 ulEvStart = "ulEvStart"
38 ulEvResetMib = "ulEvResetMib"
39 ulEvGetVendorAndSerial = "ulEvGetVendorAndSerial"
40 ulEvGetEquipmentID = "ulEvGetEquipmentId"
41 ulEvGetFirstSwVersion = "ulEvGetFirstSwVersion"
42 ulEvGetSecondSwVersion = "ulEvGetSecondSwVersion"
43 ulEvGetMacAddress = "ulEvGetMacAddress"
44 ulEvGetMibTemplate = "ulEvGetMibTemplate"
45 ulEvUploadMib = "ulEvUploadMib"
46 ulEvExamineMds = "ulEvExamineMds"
47 ulEvSuccess = "ulEvSuccess"
48 ulEvMismatch = "ulEvMismatch"
49 ulEvAuditMib = "ulEvAuditMib"
50 ulEvForceResync = "ulEvForceResync"
51 ulEvDiffsFound = "ulEvDiffsFound"
52 ulEvTimeout = "ulEvTimeout"
53 ulEvStop = "ulEvStop"
54)
55const (
56 ulStDisabled = "ulStDisabled"
57 ulStStarting = "ulStStarting"
58 ulStResettingMib = "ulStResettingMib"
59 ulStGettingVendorAndSerial = "ulStGettingVendorAndSerial"
60 ulStGettingEquipmentID = "ulStGettingEquipmentID"
61 ulStGettingFirstSwVersion = "ulStGettingFirstSwVersion"
62 ulStGettingSecondSwVersion = "ulStGettingSecondSwVersion"
63 ulStGettingMacAddress = "ulStGettingMacAddress"
64 ulStGettingMibTemplate = "ulStGettingMibTemplate"
65 ulStUploading = "ulStUploading"
66 ulStInSync = "ulStInSync"
67 ulStExaminingMds = "ulStExaminingMds"
68 ulStResynchronizing = "ulStResynchronizing"
69 ulStAuditing = "ulStAuditing"
70 ulStOutOfSync = "ulStOutOfSync"
71)
72
73const (
74 dlEvStart = "dlEvStart"
75 dlEvCreateGal = "dlEvCreateGal"
76 dlEvRxGalResp = "dlEvRxGalResp"
77 dlEvRxOnu2gResp = "dlEvRxOnu2gResp"
78 dlEvRxBridgeResp = "dlEvRxBridgeResp"
79 dlEvTimeoutSimple = "dlEvTimeoutSimple"
80 dlEvTimeoutBridge = "dlEvTimeoutBridge"
81 dlEvReset = "dlEvReset"
82 dlEvRestart = "dlEvRestart"
83)
84const (
85 dlStDisabled = "dlStDisabled"
86 dlStStarting = "dlStStarting"
87 dlStCreatingGal = "dlStCreatingGal"
88 dlStSettingOnu2g = "dlStSettingOnu2g"
89 dlStBridgeInit = "dlStBridgeInit"
90 dlStDownloaded = "dlStDownloaded"
91 dlStResetting = "dlStResetting"
92)
93
94const (
95 cBasePathMibTemplateKvStore = "service/voltha/omci_mibs/go_templates"
96 cSuffixMibTemplateKvStore = "%s/%s/%s"
97)
98
99// OnuDeviceEvent - event of interest to Device Adapters and OpenOMCI State Machines
100type OnuDeviceEvent int
101
102const (
103
104 DeviceStatusInit OnuDeviceEvent = 0
105 MibDatabaseSync OnuDeviceEvent = 1
106 OmciCapabilitiesDone OnuDeviceEvent = 2
107 MibDownloadDone OnuDeviceEvent = 3
108 UniLockStateDone OnuDeviceEvent = 4
109 UniUnlockStateDone OnuDeviceEvent = 5
110 UniAdminStateDone OnuDeviceEvent = 6
111 PortLinkUp OnuDeviceEvent = 7
112 PortLinkDw OnuDeviceEvent = 8
113 OmciAniConfigDone OnuDeviceEvent = 9
114 OmciVlanFilterDone OnuDeviceEvent = 10
115)
116
117type activityDescr struct {
118 databaseClass func() error
119 auditDelay uint16
120}
121
122// OmciDeviceFsms - FSM event mapping to database class and time to wait between audits
123type OmciDeviceFsms map[string]activityDescr
124
125// AdapterFsm - Adapter FSM details including channel, event and device
126type AdapterFsm struct {
127 fsmName string
128 deviceID string
129 commChan chan Message
130 pFsm *fsm.FSM
131}
132
133//NewAdapterFsm - FSM details including event, device and channel.
134func NewAdapterFsm(aName string, aDeviceID string, aCommChannel chan Message) *AdapterFsm {
135 aFsm := &AdapterFsm{
136 fsmName: aName,
137 deviceID: aDeviceID,
138 commChan: aCommChannel,
139 }
140 return aFsm
141}
142
143//Start starts (logs) the omci agent
144func (oo *AdapterFsm) logFsmStateChange(e *fsm.Event) {
145 logger.Debugw("FSM state change", log.Fields{"device-id": oo.deviceID, "FSM name": oo.fsmName,
146 "event name": string(e.Event), "src state": string(e.Src), "dst state": string(e.Dst)})
147}
148
149//OntDeviceEntry structure holds information about the attached FSM'as and their communication
150
151const (
152 firstSwImageMeID = 0
153 secondSwImageMeID = 1
154)
155const onugMeID = 0
156const onu2gMeID = 0
157const ipHostConfigDataMeID = 1
158const onugSerialNumberLen = 8
159const omciMacAddressLen = 6
160
161type swImages struct {
162 version string
163 isActive uint8
164}
165
166// OnuDeviceEntry - ONU device info and FSM events.
167type OnuDeviceEntry struct {
168 deviceID string
169 baseDeviceHandler *deviceHandler
170 coreProxy adapterif.CoreProxy
171 adapterProxy adapterif.AdapterProxy
172 started bool
173 PDevOmciCC *omciCC
174 pOnuDB *onuDeviceDB
175 mibTemplateKVStore *db.Backend
176 vendorID string
177 serialNumber string
178 equipmentID string
179 swImages [secondSwImageMeID + 1]swImages
180 activeSwVersion string
181 macAddress string
182 mibDbClass func() error
183 supportedFsms OmciDeviceFsms
184 devState OnuDeviceEvent
185 mibAuditDelay uint16
186 mibDebugLevel string
187
188 pMibUploadFsm *AdapterFsm //could be handled dynamically and more general as pAdapterFsm - perhaps later
189 pMibDownloadFsm *AdapterFsm //could be handled dynamically and more general as pAdapterFsm - perhaps later
190 omciMessageReceived chan bool //seperate channel needed by DownloadFsm
191 omciRebootMessageReceivedChannel chan Message // channel needed by Reboot request
192}
193
194//newOnuDeviceEntry returns a new instance of a OnuDeviceEntry
195//mib_db (as well as not inluded alarm_db not really used in this code? VERIFY!!)
196func newOnuDeviceEntry(ctx context.Context, deviceID string, kVStoreHost string, kVStorePort int, kvStoreType string, deviceHandler *deviceHandler,
197 coreProxy adapterif.CoreProxy, adapterProxy adapterif.AdapterProxy,
198 supportedFsmsPtr *OmciDeviceFsms) *OnuDeviceEntry {
199 logger.Infow("init-onuDeviceEntry", log.Fields{"device-id": deviceID})
200 var onuDeviceEntry OnuDeviceEntry
201 onuDeviceEntry.started = false
202 onuDeviceEntry.deviceID = deviceID
203 onuDeviceEntry.baseDeviceHandler = deviceHandler
204 onuDeviceEntry.coreProxy = coreProxy
205 onuDeviceEntry.adapterProxy = adapterProxy
206 onuDeviceEntry.devState = DeviceStatusInit
207 onuDeviceEntry.omciRebootMessageReceivedChannel = make(chan Message, 2048)
208 if supportedFsmsPtr != nil {
209 onuDeviceEntry.supportedFsms = *supportedFsmsPtr
210 } else {
211 //var mibSyncFsm = NewMibSynchronizer()
212 // use some internaƶ defaults, if not defined from outside
213 onuDeviceEntry.supportedFsms = OmciDeviceFsms{
214 "mib-synchronizer": {
215 //mibSyncFsm, // Implements the MIB synchronization state machine
216 onuDeviceEntry.mibDbVolatileDict, // Implements volatile ME MIB database
217 //true, // Advertise events on OpenOMCI event bus
218 60, // Time to wait between MIB audits. 0 to disable audits.
219 // map[string]func() error{
220 // "mib-upload": onuDeviceEntry.MibUploadTask,
221 // "mib-template": onuDeviceEntry.MibTemplateTask,
222 // "get-mds": onuDeviceEntry.GetMdsTask,
223 // "mib-audit": onuDeviceEntry.GetMdsTask,
224 // "mib-resync": onuDeviceEntry.MibResyncTask,
225 // "mib-reconcile": onuDeviceEntry.MibReconcileTask,
226 // },
227 },
228 }
229 }
230 onuDeviceEntry.mibDbClass = onuDeviceEntry.supportedFsms["mib-synchronizer"].databaseClass
231 logger.Debug("access2mibDbClass")
232 go onuDeviceEntry.mibDbClass()
233 onuDeviceEntry.mibAuditDelay = onuDeviceEntry.supportedFsms["mib-synchronizer"].auditDelay
234 logger.Debugw("MibAudit is set to", log.Fields{"Delay": onuDeviceEntry.mibAuditDelay})
235
236 onuDeviceEntry.mibDebugLevel = "normal" //set to "verbose" if you want to have all output, possibly later also per config option!
237 mibUploadChan := make(chan Message, 2048)
238 onuDeviceEntry.pMibUploadFsm = NewAdapterFsm("MibUpload", deviceID, mibUploadChan)
239 onuDeviceEntry.pMibUploadFsm.pFsm = fsm.NewFSM(
240 ulStDisabled,
241 fsm.Events{
242
243 {Name: ulEvStart, Src: []string{ulStDisabled}, Dst: ulStStarting},
244
245 {Name: ulEvResetMib, Src: []string{ulStStarting}, Dst: ulStResettingMib},
246 {Name: ulEvGetVendorAndSerial, Src: []string{ulStResettingMib}, Dst: ulStGettingVendorAndSerial},
247 {Name: ulEvGetEquipmentID, Src: []string{ulStGettingVendorAndSerial}, Dst: ulStGettingEquipmentID},
248 {Name: ulEvGetFirstSwVersion, Src: []string{ulStGettingEquipmentID}, Dst: ulStGettingFirstSwVersion},
249 {Name: ulEvGetSecondSwVersion, Src: []string{ulStGettingFirstSwVersion}, Dst: ulStGettingSecondSwVersion},
250 {Name: ulEvGetMacAddress, Src: []string{ulStGettingSecondSwVersion}, Dst: ulStGettingMacAddress},
251 {Name: ulEvGetMibTemplate, Src: []string{ulStGettingMacAddress}, Dst: ulStGettingMibTemplate},
252
253 {Name: ulEvUploadMib, Src: []string{ulStGettingMibTemplate}, Dst: ulStUploading},
254 {Name: ulEvExamineMds, Src: []string{ulStStarting}, Dst: ulStExaminingMds},
255
256 {Name: ulEvSuccess, Src: []string{ulStGettingMibTemplate}, Dst: ulStInSync},
257 {Name: ulEvSuccess, Src: []string{ulStUploading}, Dst: ulStInSync},
258
259 {Name: ulEvSuccess, Src: []string{ulStExaminingMds}, Dst: ulStInSync},
260 {Name: ulEvMismatch, Src: []string{ulStExaminingMds}, Dst: ulStResynchronizing},
261
262 {Name: ulEvAuditMib, Src: []string{ulStInSync}, Dst: ulStAuditing},
263
264 {Name: ulEvSuccess, Src: []string{ulStOutOfSync}, Dst: ulStInSync},
265 {Name: ulEvAuditMib, Src: []string{ulStOutOfSync}, Dst: ulStAuditing},
266
267 {Name: ulEvSuccess, Src: []string{ulStAuditing}, Dst: ulStInSync},
268 {Name: ulEvMismatch, Src: []string{ulStAuditing}, Dst: ulStResynchronizing},
269 {Name: ulEvForceResync, Src: []string{ulStAuditing}, Dst: ulStResynchronizing},
270
271 {Name: ulEvSuccess, Src: []string{ulStResynchronizing}, Dst: ulStInSync},
272 {Name: ulEvDiffsFound, Src: []string{ulStResynchronizing}, Dst: ulStOutOfSync},
273
274 {Name: ulEvTimeout, Src: []string{ulStResettingMib, ulStGettingVendorAndSerial, ulStGettingEquipmentID, ulStGettingFirstSwVersion,
275 ulStGettingSecondSwVersion, ulStGettingMacAddress, ulStGettingMibTemplate, ulStUploading, ulStResynchronizing, ulStExaminingMds,
276 ulStInSync, ulStOutOfSync, ulStAuditing}, Dst: ulStStarting},
277
278 {Name: ulEvStop, Src: []string{ulStStarting, ulStResettingMib, ulStGettingVendorAndSerial, ulStGettingEquipmentID, ulStGettingFirstSwVersion,
279 ulStGettingSecondSwVersion, ulStGettingMacAddress, ulStGettingMibTemplate, ulStUploading, ulStResynchronizing, ulStExaminingMds,
280 ulStInSync, ulStOutOfSync, ulStAuditing}, Dst: ulStDisabled},
281 },
282
283 fsm.Callbacks{
284 "enter_state": func(e *fsm.Event) { onuDeviceEntry.pMibUploadFsm.logFsmStateChange(e) },
285 ("enter_" + ulStStarting): func(e *fsm.Event) { onuDeviceEntry.enterStartingState(e) },
286 ("enter_" + ulStResettingMib): func(e *fsm.Event) { onuDeviceEntry.enterResettingMibState(e) },
287 ("enter_" + ulStGettingVendorAndSerial): func(e *fsm.Event) { onuDeviceEntry.enterGettingVendorAndSerialState(e) },
288 ("enter_" + ulStGettingEquipmentID): func(e *fsm.Event) { onuDeviceEntry.enterGettingEquipmentIDState(e) },
289 ("enter_" + ulStGettingFirstSwVersion): func(e *fsm.Event) { onuDeviceEntry.enterGettingFirstSwVersionState(e) },
290 ("enter_" + ulStGettingSecondSwVersion): func(e *fsm.Event) { onuDeviceEntry.enterGettingSecondSwVersionState(e) },
291 ("enter_" + ulStGettingMacAddress): func(e *fsm.Event) { onuDeviceEntry.enterGettingMacAddressState(e) },
292 ("enter_" + ulStGettingMibTemplate): func(e *fsm.Event) { onuDeviceEntry.enterGettingMibTemplate(e) },
293 ("enter_" + ulStUploading): func(e *fsm.Event) { onuDeviceEntry.enterUploadingState(e) },
294 ("enter_" + ulStExaminingMds): func(e *fsm.Event) { onuDeviceEntry.enterExaminingMdsState(e) },
295 ("enter_" + ulStResynchronizing): func(e *fsm.Event) { onuDeviceEntry.enterResynchronizingState(e) },
296 ("enter_" + ulStAuditing): func(e *fsm.Event) { onuDeviceEntry.enterAuditingState(e) },
297 ("enter_" + ulStOutOfSync): func(e *fsm.Event) { onuDeviceEntry.enterOutOfSyncState(e) },
298 ("enter_" + ulStInSync): func(e *fsm.Event) { onuDeviceEntry.enterInSyncState(e) },
299 },
300 )
301 mibDownloadChan := make(chan Message, 2048)
302 onuDeviceEntry.pMibDownloadFsm = NewAdapterFsm("MibDownload", deviceID, mibDownloadChan)
303 onuDeviceEntry.pMibDownloadFsm.pFsm = fsm.NewFSM(
304 dlStDisabled,
305 fsm.Events{
306
307 {Name: dlEvStart, Src: []string{dlStDisabled}, Dst: dlStStarting},
308
309 {Name: dlEvCreateGal, Src: []string{dlStStarting}, Dst: dlStCreatingGal},
310 {Name: dlEvRxGalResp, Src: []string{dlStCreatingGal}, Dst: dlStSettingOnu2g},
311 {Name: dlEvRxOnu2gResp, Src: []string{dlStSettingOnu2g}, Dst: dlStBridgeInit},
312 // the bridge state is used for multi ME config for alle UNI related ports
313 // maybe such could be reflected in the state machine as well (port number parametrized)
314 // but that looks not straightforward here - so we keep it simple here for the beginning(?)
315 {Name: dlEvRxBridgeResp, Src: []string{dlStBridgeInit}, Dst: dlStDownloaded},
316
317 {Name: dlEvTimeoutSimple, Src: []string{dlStCreatingGal, dlStSettingOnu2g}, Dst: dlStStarting},
318 {Name: dlEvTimeoutBridge, Src: []string{dlStBridgeInit}, Dst: dlStStarting},
319
320 {Name: dlEvReset, Src: []string{dlStStarting, dlStCreatingGal, dlStSettingOnu2g,
321 dlStBridgeInit, dlStDownloaded}, Dst: dlStResetting},
322 // exceptional treatment for all states except dlStResetting
323 {Name: dlEvRestart, Src: []string{dlStStarting, dlStCreatingGal, dlStSettingOnu2g,
324 dlStBridgeInit, dlStDownloaded, dlStResetting}, Dst: dlStDisabled},
325 },
326
327 fsm.Callbacks{
328 "enter_state": func(e *fsm.Event) { onuDeviceEntry.pMibDownloadFsm.logFsmStateChange(e) },
329 ("enter_" + dlStStarting): func(e *fsm.Event) { onuDeviceEntry.enterDLStartingState(e) },
330 ("enter_" + dlStCreatingGal): func(e *fsm.Event) { onuDeviceEntry.enterCreatingGalState(e) },
331 ("enter_" + dlStSettingOnu2g): func(e *fsm.Event) { onuDeviceEntry.enterSettingOnu2gState(e) },
332 ("enter_" + dlStBridgeInit): func(e *fsm.Event) { onuDeviceEntry.enterBridgeInitState(e) },
333 ("enter_" + dlStDownloaded): func(e *fsm.Event) { onuDeviceEntry.enterDownloadedState(e) },
334 ("enter_" + dlStResetting): func(e *fsm.Event) { onuDeviceEntry.enterResettingState(e) },
335 },
336 )
337 if onuDeviceEntry.pMibDownloadFsm == nil || onuDeviceEntry.pMibDownloadFsm.pFsm == nil {
338 logger.Error("MibDownloadFsm could not be instantiated!!")
339 // some specifc error treatment - or waiting for crash ???
340 }
341
342 onuDeviceEntry.mibTemplateKVStore = onuDeviceEntry.baseDeviceHandler.setBackend(cBasePathMibTemplateKvStore)
343 if onuDeviceEntry.mibTemplateKVStore == nil {
344 logger.Errorw("Failed to setup mibTemplateKVStore", log.Fields{"device-id": deviceID})
345 }
346
347 return &onuDeviceEntry
348}
349
350//start starts (logs) the omci agent
351func (oo *OnuDeviceEntry) start(ctx context.Context) error {
352 logger.Info("starting-OnuDeviceEntry")
353
354 oo.PDevOmciCC = newOmciCC(ctx, oo, oo.deviceID, oo.baseDeviceHandler,
355 oo.coreProxy, oo.adapterProxy)
356 if oo.PDevOmciCC == nil {
357 logger.Errorw("Could not create devOmciCc - abort", log.Fields{"for device-id": oo.deviceID})
358 return errors.New("could not create devOmciCc")
359 }
360
361 oo.started = true
362 logger.Info("OnuDeviceEntry-started")
363 return nil
364}
365
366//stop terminates the session
367func (oo *OnuDeviceEntry) stop(ctx context.Context) error {
368 logger.Info("stopping-OnuDeviceEntry")
369 oo.started = false
370 logger.Info("OnuDeviceEntry-stopped")
371 return nil
372}
373
374func (oo *OnuDeviceEntry) reboot(ctx context.Context) error {
375 logger.Info("reboot-OnuDeviceEntry")
376 if err := oo.PDevOmciCC.sendReboot(context.TODO(), ConstDefaultOmciTimeout, true, oo.omciRebootMessageReceivedChannel); err != nil {
377 logger.Errorw("onu didn't reboot", log.Fields{"for device-id": oo.deviceID})
378 return err
379 }
380 logger.Info("OnuDeviceEntry-reboot")
381 return nil
382}
383
384func (oo *OnuDeviceEntry) waitForRebootResponse(responseChannel chan Message) error {
385 select {
386 case <-time.After(3 * time.Second): //3s was detected to be to less in 8*8 bbsim test with debug Info/Debug
387 logger.Warnw("Reboot timeout", log.Fields{"for device-id": oo.deviceID})
388 return errors.New("rebootTimeout")
389 case data := <-responseChannel:
390 switch data.Data.(OmciMessage).OmciMsg.MessageType {
391 case omci.RebootResponseType:
392 {
393 msgLayer := (*data.Data.(OmciMessage).OmciPacket).Layer(omci.LayerTypeRebootResponse)
394 if msgLayer == nil {
395 return errors.New("omci Msg layer could not be detected for RebootResponseType")
396 }
397 msgObj, msgOk := msgLayer.(*omci.GetResponse)
398 if !msgOk {
399 return errors.New("omci Msg layer could not be assigned for RebootResponseType")
400 }
401 logger.Debugw("CreateResponse Data", log.Fields{"device-id": oo.deviceID, "data-fields": msgObj})
402 if msgObj.Result != me.Success {
403 logger.Errorw("Omci RebootResponseType Error ", log.Fields{"Error": msgObj.Result})
404 // possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
405 return errors.New("omci RebootResponse Result Error indication")
406 }
407 return nil
408 }
409 }
410 logger.Warnw("Reboot response error", log.Fields{"for device-id": oo.deviceID})
411 return errors.New("unexpected OmciResponse type received")
412 }
413}
414
415//Relay the InSync message via Handler to Rw core - Status update
416func (oo *OnuDeviceEntry) transferSystemEvent(devEvent OnuDeviceEvent) {
417 logger.Debugw("relaying system-event", log.Fields{"Event": devEvent})
418 if devEvent == MibDatabaseSync {
419 if oo.devState < MibDatabaseSync { //devState has not been synced yet
420 oo.devState = MibDatabaseSync
421 go oo.baseDeviceHandler.deviceProcStatusUpdate(devEvent)
422 //TODO!!! device control: next step: start MIB capability verification from here ?!!!
423 } else {
424 logger.Debugw("mibinsync-event in some already synced state - ignored", log.Fields{"state": oo.devState})
425 }
426 } else if devEvent == MibDownloadDone {
427 if oo.devState < MibDownloadDone { //devState has not been synced yet
428 oo.devState = MibDownloadDone
429 go oo.baseDeviceHandler.deviceProcStatusUpdate(devEvent)
430 } else {
431 logger.Debugw("mibdownloaddone-event was already seen - ignored", log.Fields{"state": oo.devState})
432 }
433 } else {
434 logger.Warnw("device-event not yet handled", log.Fields{"state": devEvent})
435 }
436}