blob: e40c85434715d832e924371e5b98542197054291 [file] [log] [blame]
Matteo Scandolo11006992019-08-28 11:29:46 -07001/*
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 */
16
Matteo Scandolo4747d292019-08-05 11:50:18 -070017package devices
18
19import (
Matteo Scandolo40e067f2019-10-16 16:59:41 -070020 "context"
Himani Chawla4ff5fab2021-11-09 19:19:29 +053021 "encoding/binary"
Matteo Scandolo618a6582020-09-09 12:21:29 -070022 "encoding/hex"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070023 "fmt"
Mahir Gunyela1753ae2021-06-23 00:24:56 -070024 "sync"
25
Matteo Scandolo8a574812021-05-20 15:18:53 -070026 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
27 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
28 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000029
Matteo Scandolof9d43412021-01-12 11:11:34 -080030 pb "github.com/opencord/bbsim/api/bbsim"
31 "github.com/opencord/bbsim/internal/bbsim/alarmsim"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000032
33 "net"
34 "strconv"
35 "time"
Himani Chawla13b1ee02021-03-15 01:43:53 +053036
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080037 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Andrea Campanella10426e22021-10-15 17:58:04 +020038 me "github.com/opencord/omci-lib-go/v2/generated"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010039
Himani Chawla4ff5fab2021-11-09 19:19:29 +053040 "github.com/boguslaw-wojcik/crc32a"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070041 "github.com/google/gopacket/layers"
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070042 "github.com/jpillora/backoff"
Matteo Scandolo4747d292019-08-05 11:50:18 -070043 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070044 "github.com/opencord/bbsim/internal/common"
45 omcilib "github.com/opencord/bbsim/internal/common/omci"
Andrea Campanella10426e22021-10-15 17:58:04 +020046 "github.com/opencord/omci-lib-go/v2"
David K. Bainbridgec415efe2021-08-19 13:05:21 +000047 "github.com/opencord/voltha-protos/v5/go/openolt"
48 "github.com/opencord/voltha-protos/v5/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070049 log "github.com/sirupsen/logrus"
50)
51
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070052var onuLogger = log.WithFields(log.Fields{
53 "module": "ONU",
54})
55
Matteo Scandolocedde462021-03-09 17:37:16 -080056const (
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000057 maxOmciMsgCounter = 10
58)
59
60const (
Matteo Scandolocedde462021-03-09 17:37:16 -080061 // ONU transitions
62 OnuTxInitialize = "initialize"
63 OnuTxDiscover = "discover"
64 OnuTxEnable = "enable"
65 OnuTxDisable = "disable"
66 OnuTxPonDisable = "pon_disable"
67 OnuTxStartImageDownload = "start_image_download"
68 OnuTxProgressImageDownload = "progress_image_download"
69 OnuTxCompleteImageDownload = "complete_image_download"
70 OnuTxFailImageDownload = "fail_image_download"
71 OnuTxActivateImage = "activate_image"
72 OnuTxCommitImage = "commit_image"
73
74 // ONU States
75 OnuStateCreated = "created"
76 OnuStateInitialized = "initialized"
77 OnuStateDiscovered = "discovered"
78 OnuStateEnabled = "enabled"
79 OnuStateDisabled = "disabled"
80 OnuStatePonDisabled = "pon_disabled"
81 OnuStateImageDownloadStarted = "image_download_started"
82 OnuStateImageDownloadInProgress = "image_download_in_progress"
83 OnuStateImageDownloadComplete = "image_download_completed"
84 OnuStateImageDownloadError = "image_download_error"
85 OnuStateImageActivated = "software_image_activated"
86 OnuStateImageCommitted = "software_image_committed"
87
88 // BBR ONU States and Transitions
89 BbrOnuTxSendEapolFlow = "send_eapol_flow"
90 BbrOnuStateEapolFlowSent = "eapol_flow_sent"
91 BbrOnuTxSendDhcpFlow = "send_dhcp_flow"
92 BbrOnuStateDhcpFlowSent = "dhcp_flow_sent"
93)
94
Pragya Arya8bdb4532020-03-02 17:08:09 +053095type FlowKey struct {
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070096 ID uint64
Pragya Arya8bdb4532020-03-02 17:08:09 +053097 Direction string
98}
99
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700100type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800101 ID uint32
102 PonPortID uint32
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700103 PonPort *PonPort
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800104 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +0530105 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
106 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandolo4a036262020-08-17 15:56:13 -0700107
Matteo Scandolo4a036262020-08-17 15:56:13 -0700108 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800109 // ONU State
Matteo Scandolo8a574812021-05-20 15:18:53 -0700110 UniPorts []UniPortIf
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700111 Flows []FlowKey
112 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700113
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700114 OperState *fsm.FSM
115 SerialNumber *openolt.SerialNumber
116
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700117 AdminLockState uint8 // 0 is enabled, 1 is disabled.
118
Matteo Scandolof9d43412021-01-12 11:11:34 -0800119 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700120
121 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800122 MibDataSync uint8
123 ImageSoftwareExpectedSections int
124 ImageSoftwareReceivedSections int
125 ActiveImageEntityId uint16
126 CommittedImageEntityId uint16
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700127 StandbyImageVersion string
128 ActiveImageVersion string
Matteo Scandolo76f6b892021-11-15 16:13:06 -0800129 InDownloadImageVersion string
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700130 CommittedImageVersion string
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000131 OmciResponseRate uint8
132 OmciMsgCounter uint8
Himani Chawla4ff5fab2021-11-09 19:19:29 +0530133 ImageSectionData []byte
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800134
135 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700136 tid uint16
137 hpTid uint16
138 seqNumber uint16
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700139 MibDb *omcilib.MibDb
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700140
Anand S Katti09541352020-01-29 15:54:01 +0530141 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
142 TrafficSchedulers *tech_profile.TrafficSchedulers
Himani Chawla13b1ee02021-03-15 01:43:53 +0530143 onuAlarmsInfoLock sync.RWMutex
144 onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700145}
146
Matteo Scandolo99f18462019-10-28 14:14:28 -0700147func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700148 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700149}
150
Matteo Scandolo8a574812021-05-20 15:18:53 -0700151func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, nextCtag map[string]int, nextStag map[string]int, isMock bool) *Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700152
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700153 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800154 ID: id,
155 PonPortID: pon.ID,
156 PonPort: pon,
Matteo Scandolocedde462021-03-09 17:37:16 -0800157 tid: 0x1,
158 hpTid: 0x8000,
159 seqNumber: 0,
160 DoneChannel: make(chan bool, 1),
161 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
162 Flows: []FlowKey{},
163 DiscoveryDelay: delay,
164 MibDataSync: 0,
165 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
166 ImageSoftwareReceivedSections: 0,
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700167 //TODO this needs reworking, it's always 0 or 1, possibly base all on the version
168 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
169 CommittedImageEntityId: 0,
170 StandbyImageVersion: "BBSM_IMG_00000",
171 ActiveImageVersion: "BBSM_IMG_00001",
172 CommittedImageVersion: "BBSM_IMG_00001",
173 OmciResponseRate: olt.OmciResponseRate,
174 OmciMsgCounter: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700175 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800176 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700177 // NOTE this state machine is used to track the operational
178 // state as requested by VOLTHA
179 o.OperState = getOperStateFSM(func(e *fsm.Event) {
180 onuLogger.WithFields(log.Fields{
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700181 "OnuId": o.ID,
182 "IntfId": o.PonPortID,
183 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700184 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
185 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530186 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700187 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
188 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800189 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700190 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700191 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800192 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
193 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
194 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100195 // NOTE should disabled state be different for oper_disabled (emulating an error) and admin_disabled (received a disabled call via VOLTHA)?
Matteo Scandolocedde462021-03-09 17:37:16 -0800196 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530197 // ONU state when PON port is disabled but ONU is power ON(more states should be added in src?)
Matteo Scandolo9f4bf4f2021-06-22 09:41:02 +0200198 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted, OnuStateImageDownloadComplete}, Dst: OnuStatePonDisabled},
Matteo Scandolocedde462021-03-09 17:37:16 -0800199 // Software Image Download related states
Matteo Scandolo9f4bf4f2021-06-22 09:41:02 +0200200 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateImageDownloadStarted},
Matteo Scandolocedde462021-03-09 17:37:16 -0800201 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
202 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
203 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
204 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
205 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700206 // BBR States
207 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800208 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
209 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700210 },
211 fsm.Callbacks{
212 "enter_state": func(e *fsm.Event) {
213 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700214 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700215 fmt.Sprintf("enter_%s", OnuStateInitialized): func(e *fsm.Event) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100216 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800217 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800218
Matteo Scandolocedde462021-03-09 17:37:16 -0800219 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800220 onuLogger.WithFields(log.Fields{
221 "OnuId": o.ID,
222 "IntfId": o.PonPortID,
223 "OnuSn": o.Sn(),
224 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
225 }
226
Pragya Arya1cbefa42020-01-13 12:15:29 +0530227 if !isMock {
228 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700229 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530230 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100231 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700232 fmt.Sprintf("enter_%s", OnuStateDiscovered): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800233 msg := bbsim.Message{
234 Type: bbsim.OnuDiscIndication,
235 Data: bbsim.OnuDiscIndicationMessage{
236 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100237 },
238 }
239 o.Channel <- msg
240 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700241 fmt.Sprintf("enter_%s", OnuStateEnabled): func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800242
243 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
244 onuLogger.WithFields(log.Fields{
245 "IntfId": o.PonPortID,
246 "OnuId": o.ID,
247 "SerialNumber": o.Sn(),
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700248 }).Errorf("onu-id-duplicated-with-%s", common.OnuSnToString(sn))
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800249 return
250 } else {
251 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
252 }
253
Matteo Scandolof9d43412021-01-12 11:11:34 -0800254 msg := bbsim.Message{
255 Type: bbsim.OnuIndication,
256 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700257 OnuSN: o.SerialNumber,
258 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800259 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700260 },
261 }
262 o.Channel <- msg
263 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700264 fmt.Sprintf("enter_%s", OnuStateDisabled): func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700265
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700266 o.cleanupOnuState()
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700267
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700268 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800269 if err := o.OperState.Event("disable"); err != nil {
270 onuLogger.WithFields(log.Fields{
271 "OnuId": o.ID,
272 "IntfId": o.PonPortID,
273 "OnuSn": o.Sn(),
274 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
275 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700276 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800277 msg := bbsim.Message{
278 Type: bbsim.OnuIndication,
279 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700280 OnuSN: o.SerialNumber,
281 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800282 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700283 },
284 }
285 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530286
Matteo Scandolo8a574812021-05-20 15:18:53 -0700287 // disable the UNI ports
288 for _, uni := range o.UniPorts {
289 _ = uni.Disable()
290 }
291
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530292 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100293 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolo8a574812021-05-20 15:18:53 -0700294 // NOTE may need to wait for the UNIs to be down too before shutting down the channel
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530295 if len(o.FlowIds) == 0 {
296 close(o.Channel)
297 }
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700298 },
299 fmt.Sprintf("enter_%s", OnuStatePonDisabled): func(event *fsm.Event) {
300 o.cleanupOnuState()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700301 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700302 // BBR states
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700303 fmt.Sprintf("enter_%s", BbrOnuStateEapolFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800304 msg := bbsim.Message{
305 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700306 }
307 o.Channel <- msg
308 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700309 fmt.Sprintf("enter_%s", BbrOnuStateDhcpFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800310 msg := bbsim.Message{
311 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700312 }
313 o.Channel <- msg
314 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700315 },
316 )
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700317 onuLogger.WithFields(log.Fields{
318 "OnuId": o.ID,
319 "IntfId": o.PonPortID,
320 "OnuSn": o.Sn(),
321 "NumUni": olt.NumUni,
322 }).Debug("creating-uni-ports")
323 for i := 0; i < olt.NumUni; i++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700324 uni, err := NewUniPort(uint32(i), &o, nextCtag, nextStag)
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700325 if err != nil {
326 onuLogger.WithFields(log.Fields{
327 "OnuId": o.ID,
328 "IntfId": o.PonPortID,
329 "OnuSn": o.Sn(),
330 "Err": err,
331 }).Fatal("cannot-create-uni-port")
332 }
333 o.UniPorts = append(o.UniPorts, uni)
334 }
335
336 mibDb, err := omcilib.GenerateMibDatabase(len(o.UniPorts))
337 if err != nil {
338 onuLogger.WithFields(log.Fields{
339 "OnuId": o.ID,
340 "IntfId": o.PonPortID,
341 "OnuSn": o.Sn(),
342 }).Fatal("cannot-generate-mibdb-for-onu")
343 }
344 o.MibDb = mibDb
345
Matteo Scandolo27428702019-10-11 16:21:16 -0700346 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700347}
348
William Kurkian0418bc82019-11-06 12:16:24 -0500349func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700350 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700351 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700352 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700353 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700354 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
355}
356
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700357// cleanupOnuState this method is to clean the local state when the ONU is disabled
358func (o *Onu) cleanupOnuState() {
359 // clean the ONU state
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700360 o.Flows = []FlowKey{}
361 o.PonPort.removeOnuId(o.ID)
362 o.PonPort.removeAllocId(o.SerialNumber)
363 o.PonPort.removeGemPortBySn(o.SerialNumber)
364
365 o.onuAlarmsInfoLock.Lock()
366 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
367 o.onuAlarmsInfoLock.Unlock()
368}
369
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100370// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000371func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700372 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100373 "onuID": o.ID,
374 "onuSN": o.Sn(),
375 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700376 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100377 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700378
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700379 defer onuLogger.WithFields(log.Fields{
380 "onuID": o.ID,
381 "onuSN": o.Sn(),
382 "stream": stream,
383 }).Debug("Stopped handling ONU Indication Channel")
384
David Bainbridge103cf022019-12-16 20:11:35 +0000385loop:
386 for {
387 select {
388 case <-ctx.Done():
389 onuLogger.WithFields(log.Fields{
390 "onuID": o.ID,
391 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700392 }).Debug("ONU message handling canceled via context")
393 break loop
394 case <-stream.Context().Done():
395 onuLogger.WithFields(log.Fields{
396 "onuID": o.ID,
397 "onuSN": o.Sn(),
398 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000399 break loop
400 case message, ok := <-o.Channel:
401 if !ok || ctx.Err() != nil {
402 onuLogger.WithFields(log.Fields{
403 "onuID": o.ID,
404 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700405 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000406 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700407 }
David Bainbridge103cf022019-12-16 20:11:35 +0000408 onuLogger.WithFields(log.Fields{
409 "onuID": o.ID,
410 "onuSN": o.Sn(),
411 "messageType": message.Type,
412 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700413
David Bainbridge103cf022019-12-16 20:11:35 +0000414 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800415 case bbsim.OnuDiscIndication:
416 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000417 // NOTE we need to slow down and send ONU Discovery Indication in batches to better emulate a real scenario
Pragya Arya2225f202020-01-29 18:05:01 +0530418 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000419 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800420 case bbsim.OnuIndication:
421 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000422 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800423 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800424 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800425 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200426 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800427 case bbsim.UniStatusAlarm:
428 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530429 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
430 MeInstance: msg.EntityID,
431 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
432 }
433 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
434 o.onuAlarmsInfoLock.Lock()
435 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
436 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
437 if pkt != nil { //pkt will be nil if we are unable to create the alarm
438 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
439 onuLogger.WithFields(log.Fields{
440 "IntfId": o.PonPortID,
441 "SerialNumber": o.Sn(),
442 "omciPacket": pkt,
443 "adminState": msg.AdminState,
444 "entityID": msg.EntityID,
445 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
446 alarmInfo.SequenceNo--
447 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800448 onuLogger.WithFields(log.Fields{
449 "IntfId": o.PonPortID,
450 "SerialNumber": o.Sn(),
451 "omciPacket": pkt,
452 "adminState": msg.AdminState,
453 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530454 }).Trace("UNI-Link-alarm-sent")
455 if alarmBitMap == [28]byte{0} {
456 delete(o.onuAlarmsInfo, onuAlarmMapKey)
457 } else {
458 alarmInfo.AlarmBitMap = alarmBitMap
459 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
460 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800461 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530462 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800463 case bbsim.FlowAdd:
464 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700465 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800466 case bbsim.FlowRemoved:
467 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700468 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800469 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700470
Matteo Scandolof9d43412021-01-12 11:11:34 -0800471 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000472
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700473 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000474 "IntfId": msg.IntfId,
475 "OnuId": msg.OnuId,
476 "pktType": msg.Type,
477 }).Trace("Received OnuPacketOut Message")
478
Matteo Scandolo8a574812021-05-20 15:18:53 -0700479 uni, err := o.findUniByPortNo(msg.PortNo)
Matteo Scandolo618a6582020-09-09 12:21:29 -0700480
Matteo Scandolo8a574812021-05-20 15:18:53 -0700481 if err != nil {
482 onuLogger.WithFields(log.Fields{
483 "IntfId": msg.IntfId,
484 "OnuId": msg.OnuId,
485 "pktType": msg.Type,
486 "portNo": msg.PortNo,
487 "MacAddress": msg.MacAddress,
488 "Pkt": hex.EncodeToString(msg.Packet.Data()),
489 "OnuSn": o.Sn(),
490 }).Error("Cannot find Uni associated with packet")
491 return
David Bainbridge103cf022019-12-16 20:11:35 +0000492 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700493 uni.PacketCh <- msg
494 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800495 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000496 // NOTE we only receive BBR packets here.
497 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
498 // in the DHCP case VOLTHA only act as a proxy, the behaviour is completely different thus we have a dhcp.HandleNextBbrPacket
Matteo Scandolof9d43412021-01-12 11:11:34 -0800499 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000500
Matteo Scandolo8a574812021-05-20 15:18:53 -0700501 onuLogger.WithFields(log.Fields{
502 "IntfId": msg.IntfId,
503 "OnuId": msg.OnuId,
504 "PortNo": msg.PortNo,
505 "GemPortId": msg.GemPortId,
506 "pktType": msg.Type,
David Bainbridge103cf022019-12-16 20:11:35 +0000507 }).Trace("Received OnuPacketIn Message")
508
Matteo Scandolo8a574812021-05-20 15:18:53 -0700509 uni, err := o.findUniByPortNo(msg.PortNo)
510 if err != nil {
511 onuLogger.WithFields(log.Fields{
512 "IntfId": msg.IntfId,
513 "OnuId": msg.OnuId,
514 "PortNo": msg.PortNo,
515 "GemPortId": msg.GemPortId,
516 "pktType": msg.Type,
517 }).Error(err.Error())
518 }
519
520 // BBR has one service and one UNI
521 serviceId := uint32(0)
522 oltId := 0
David Bainbridge103cf022019-12-16 20:11:35 +0000523 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700524 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, msg.GemPortId, o.Sn(), msg.PortNo, uni.ID, serviceId, oltId, o.InternalState, msg.Packet, stream, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000525 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700526 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000527 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800528 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800529 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800530 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
531 o.handleOmciResponse(msg, client)
532 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000533 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800534 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000535 o.sendDhcpFlow(client)
536 default:
537 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700538 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700539 }
540 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700541}
542
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800543func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700544 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700545 sn.VendorId = []byte("BBSM")
546 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700547 return sn
548}
549
Matteo Scandolof9d43412021-01-12 11:11:34 -0800550func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700551 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800552 IntfId: o.PonPortID,
553 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700554 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700555
Matteo Scandolo4747d292019-08-05 11:50:18 -0700556 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700557 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700558 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700559 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700560
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700561 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800562 "IntfId": o.PonPortID,
563 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700564 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700565 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800566 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800567
568 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
569 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800570 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800571 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800572 o.sendOnuDiscIndication(msg, stream)
573 }
574 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700575}
576
Matteo Scandolof9d43412021-01-12 11:11:34 -0800577func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800578 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
579 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700580
581 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700582 IntfId: o.PonPortID,
583 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700584 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700585 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700586 SerialNumber: o.SerialNumber,
587 }}
588 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800589 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700590 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700591 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700592 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700593 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800594 "IntfId": o.PonPortID,
595 "OnuId": o.ID,
596 "VolthaOnuId": msg.OnuID,
597 "OperState": msg.OperState.String(),
598 "AdminState": msg.OperState.String(),
599 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700600 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700601
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700602}
603
Matteo Scandolof9d43412021-01-12 11:11:34 -0800604func (o *Onu) HandleShutdownONU() error {
605
606 dyingGasp := pb.ONUAlarmRequest{
607 AlarmType: "DYING_GASP",
608 SerialNumber: o.Sn(),
609 Status: "on",
610 }
611
612 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
613 onuLogger.WithFields(log.Fields{
614 "OnuId": o.ID,
615 "IntfId": o.PonPortID,
616 "OnuSn": o.Sn(),
617 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
618 return err
619 }
620
621 losReq := pb.ONUAlarmRequest{
622 AlarmType: "ONU_ALARM_LOS",
623 SerialNumber: o.Sn(),
624 Status: "on",
625 }
626
627 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
628 onuLogger.WithFields(log.Fields{
629 "OnuId": o.ID,
630 "IntfId": o.PonPortID,
631 "OnuSn": o.Sn(),
632 }).Errorf("Cannot send LOS: %s", err.Error())
633
634 return err
635 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530636 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800637 // TODO if it's the last ONU on the PON, then send a PON LOS
638
Matteo Scandolocedde462021-03-09 17:37:16 -0800639 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800640 onuLogger.WithFields(log.Fields{
641 "OnuId": o.ID,
642 "IntfId": o.PonPortID,
643 "OnuSn": o.Sn(),
644 }).Errorf("Cannot shutdown ONU: %s", err.Error())
645 return err
646 }
647
648 return nil
649}
650
651func (o *Onu) HandlePowerOnONU() error {
652 intitalState := o.InternalState.Current()
653
654 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800655 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
656 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800657 onuLogger.WithFields(log.Fields{
658 "OnuId": o.ID,
659 "IntfId": o.PonPortID,
660 "OnuSn": o.Sn(),
661 }).Errorf("Cannot poweron ONU: %s", err.Error())
662 return err
663 }
664 }
665
666 // turn off the LOS Alarm
667 losReq := pb.ONUAlarmRequest{
668 AlarmType: "ONU_ALARM_LOS",
669 SerialNumber: o.Sn(),
670 Status: "off",
671 }
672
673 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
674 onuLogger.WithFields(log.Fields{
675 "OnuId": o.ID,
676 "IntfId": o.PonPortID,
677 "OnuSn": o.Sn(),
678 }).Errorf("Cannot send LOS: %s", err.Error())
679 return err
680 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530681 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800682
683 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800684 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800685 onuLogger.WithFields(log.Fields{
686 "OnuId": o.ID,
687 "IntfId": o.PonPortID,
688 "OnuSn": o.Sn(),
689 }).Errorf("Cannot poweron ONU: %s", err.Error())
690 return err
691 }
692
693 // move o directly to enable state only when its a powercycle case
694 // in case of first time o poweron o will be moved to enable on
695 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800696 if intitalState == OnuStateDisabled {
697 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800698 onuLogger.WithFields(log.Fields{
699 "OnuId": o.ID,
700 "IntfId": o.PonPortID,
701 "OnuSn": o.Sn(),
702 }).Errorf("Cannot enable ONU: %s", err.Error())
703 return err
704 }
705 }
706
707 return nil
708}
709
710func (o *Onu) SetAlarm(alarmType string, status string) error {
711 alarmReq := pb.ONUAlarmRequest{
712 AlarmType: alarmType,
713 SerialNumber: o.Sn(),
714 Status: status,
715 }
716
717 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
718 if err != nil {
719 return err
720 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530721 raiseAlarm := false
722 if alarmReq.Status == "on" {
723 raiseAlarm = true
724 }
725 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800726 return nil
727}
728
729func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530730 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700731 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530732 if err != nil {
733 log.Errorf("error in getting msgType %v", err)
734 return
735 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800736 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530737 o.seqNumber = 0
738 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800739 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530740 o.seqNumber++
741 if o.seqNumber > 290 {
742 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
743 }
744 }
745 }
746}
747
Matteo Scandolof9d43412021-01-12 11:11:34 -0800748// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
749// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200750func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800751
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700752 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700753 "omciMsgType": msg.OmciMsg.MessageType,
754 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
755 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700756 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700757 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800758 }).Trace("omci-message-decoded")
759
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000760 if o.OmciMsgCounter < maxOmciMsgCounter {
761 o.OmciMsgCounter++
762 } else {
763 o.OmciMsgCounter = 1
764 }
765 if o.OmciMsgCounter > o.OmciResponseRate {
766 onuLogger.WithFields(log.Fields{
767 "OmciMsgCounter": o.OmciMsgCounter,
768 "OmciResponseRate": o.OmciResponseRate,
769 "omciMsgType": msg.OmciMsg.MessageType,
Matteo Scandoloa96e2242021-09-28 10:13:17 -0700770 "txId": msg.OmciMsg.TransactionID,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200771 }).Debug("skipping-omci-msg-response")
772 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000773 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800774 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800775 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700776 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800777 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800778 onuLogger.WithFields(log.Fields{
779 "IntfId": o.PonPortID,
780 "OnuId": o.ID,
781 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700782 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700783 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800784 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700785
786 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
787 o.PonPort.removeAllocId(o.SerialNumber)
788 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800789 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800790 case omci.MibUploadRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700791 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800792 case omci.MibUploadNextRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700793 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800794 case omci.GetRequestType:
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700795 onuDown := o.AdminLockState == 1
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700796 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId,
797 o.CommittedImageEntityId, o.StandbyImageVersion, o.ActiveImageVersion, o.CommittedImageVersion, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800798 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800799 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700800 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800801 switch msgObj.EntityClass {
802 case me.PhysicalPathTerminationPointEthernetUniClassID:
803 // if we're Setting a PPTP state
Matteo Scandolo8a574812021-05-20 15:18:53 -0700804 // we need to send the appropriate alarm (handled in the UNI struct)
805 uni, err := o.FindUniByEntityId(msgObj.EntityInstance)
806 if err != nil {
807 onuLogger.Error(err)
808 success = false
809 } else {
810 // 1 locks the UNI, 0 unlocks it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800811 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700812 var err error
Himani Chawla13b1ee02021-03-15 01:43:53 +0530813 if adminState == 1 {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700814 err = uni.Disable()
Girish Gowdra996d81e2021-04-21 16:16:27 -0700815 } else {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700816 err = uni.Enable()
Himani Chawla13b1ee02021-03-15 01:43:53 +0530817 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700818 if err != nil {
819 onuLogger.WithFields(log.Fields{
820 "IntfId": o.PonPortID,
821 "OnuId": o.ID,
822 "UniMeId": uni.MeId,
823 "UniId": uni.ID,
824 "SerialNumber": o.Sn(),
825 "Err": err.Error(),
826 }).Warn("cannot-change-uni-status")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800827 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800828 }
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700829 case me.OnuGClassID:
830 o.AdminLockState = msgObj.Attributes["AdministrativeState"].(uint8)
831 onuLogger.WithFields(log.Fields{
832 "IntfId": o.PonPortID,
833 "OnuId": o.ID,
834 "SerialNumber": o.Sn(),
835 "AdminLockState": o.AdminLockState,
836 }).Debug("set-onu-admin-lock-state")
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800837 case me.TContClassID:
838 allocId := msgObj.Attributes["AllocId"].(uint16)
839
840 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
841 // otherwise we are adding it
842 if allocId == 255 || allocId == 65535 {
843 onuLogger.WithFields(log.Fields{
844 "IntfId": o.PonPortID,
845 "OnuId": o.ID,
846 "TContId": msgObj.EntityInstance,
847 "AllocId": allocId,
848 "SerialNumber": o.Sn(),
849 }).Trace("freeing-alloc-id-via-omci")
850 o.PonPort.removeAllocId(o.SerialNumber)
851 } else {
852 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
853 onuLogger.WithFields(log.Fields{
854 "IntfId": o.PonPortID,
855 "OnuId": o.ID,
856 "AllocId": allocId,
857 "SerialNumber": o.Sn(),
858 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
859 success = false
860 } else {
861 onuLogger.WithFields(log.Fields{
862 "IntfId": o.PonPortID,
863 "OnuId": o.ID,
864 "TContId": msgObj.EntityInstance,
865 "AllocId": allocId,
866 "SerialNumber": o.Sn(),
867 }).Trace("storing-alloc-id-via-omci")
868 o.PonPort.storeAllocId(allocId, o.SerialNumber)
869 }
870 }
871
872 }
873
874 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700875 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800876 o.MibDataSync++
877 }
878 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700879 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800880 }
881 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800882 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
883 var used bool
884 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700885 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800886 if err == nil {
887 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700888 // GemPort 4069 is reserved for multicast and shared across ONUs
889 if msgObj.EntityInstance != 4069 {
890 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
891 onuLogger.WithFields(log.Fields{
892 "IntfId": o.PonPortID,
893 "OnuId": o.ID,
894 "GemPortId": msgObj.EntityInstance,
895 "SerialNumber": o.Sn(),
896 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
897 } else {
898 onuLogger.WithFields(log.Fields{
899 "IntfId": o.PonPortID,
900 "OnuId": o.ID,
901 "GemPortId": msgObj.EntityInstance,
902 "SerialNumber": o.Sn(),
903 }).Trace("storing-gem-port-id-via-omci")
904 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
905 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800906 }
907 }
908 }
909
910 // if the gemPort is valid then increment the MDS and return a successful response
911 // otherwise fail the request
912 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
913 // validation this check will need to be rewritten
914 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700915 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800916 o.MibDataSync++
917 }
918 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700919 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800920 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800921 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700922 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800923 if err == nil {
924 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
925 onuLogger.WithFields(log.Fields{
926 "IntfId": o.PonPortID,
927 "OnuId": o.ID,
928 "GemPortId": msgObj.EntityInstance,
929 "SerialNumber": o.Sn(),
930 }).Trace("freeing-gem-port-id-via-omci")
931 o.PonPort.removeGemPort(msgObj.EntityInstance)
932 }
933 }
934
Matteo Scandolob5913142021-03-19 16:10:18 -0700935 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800936 o.MibDataSync++
937 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800938 case omci.RebootRequestType:
939
Matteo Scandolob5913142021-03-19 16:10:18 -0700940 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800941
942 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800943 // we run this in a separate goroutine so that
944 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800945 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800946 if err := o.Reboot(10 * time.Second); err != nil {
947 log.WithFields(log.Fields{
948 "IntfId": o.PonPortID,
949 "OnuId": o.ID,
950 "SerialNumber": o.Sn(),
951 "err": err,
952 }).Error("cannot-reboot-onu-after-omci-reboot-request")
953 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800954 }()
955 case omci.TestRequestType:
Girish Gowdra161d27a2021-05-05 12:01:44 -0700956 var classID me.ClassID
957 var omciResult me.Results
958 var instID uint16
959 responsePkt, errResp, classID, instID, omciResult = omcilib.CreateTestResponse(msg.OmciPkt, msg.OmciMsg)
960 // Send TestResult only in case the TestResponse omci result code is me.Success
961 if responsePkt != nil && errResp == nil && omciResult == me.Success {
962 if testResultPkt, err := omcilib.CreateTestResult(classID, instID, msg.OmciMsg.TransactionID); err == nil {
963 // send test results asynchronously
964 go func() {
965 // Send test results after a second to emulate async behavior
966 time.Sleep(1 * time.Second)
967 if testResultPkt != nil {
968 if err := o.sendOmciIndication(testResultPkt, msg.OmciMsg.TransactionID, stream); err != nil {
969 onuLogger.WithFields(log.Fields{
970 "IntfId": o.PonPortID,
971 "SerialNumber": o.Sn(),
972 "omciPacket": testResultPkt,
973 "msg.OmciMsgType": msg.OmciMsg.MessageType,
974 "transCorrId": msg.OmciMsg.TransactionID,
975 }).Errorf("failed-to-send-omci-message: %v", err)
976 }
977 }
978 }()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800979 }
980 }
Girish Gowdraa539f522021-02-15 23:00:45 -0800981 case omci.SynchronizeTimeRequestType:
982 // MDS counter increment is not required for this message type
Matteo Scandolob5913142021-03-19 16:10:18 -0700983 responsePkt, _ = omcilib.CreateSyncTimeResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -0800984 case omci.StartSoftwareDownloadRequestType:
985
986 o.ImageSoftwareReceivedSections = 0
Himani Chawla4ff5fab2021-11-09 19:19:29 +0530987 o.ImageSectionData = []byte{}
Matteo Scandolob5913142021-03-19 16:10:18 -0700988 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
Matteo Scandolocedde462021-03-09 17:37:16 -0800989
Matteo Scandolob5913142021-03-19 16:10:18 -0700990 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -0800991 o.MibDataSync++
992 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
993 onuLogger.WithFields(log.Fields{
994 "OnuId": o.ID,
995 "IntfId": o.PonPortID,
996 "OnuSn": o.Sn(),
997 "Err": err.Error(),
998 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
999 }
1000 } else {
1001 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001002 "OmciMsgType": msg.OmciMsg.MessageType,
1003 "TransCorrId": msg.OmciMsg.TransactionID,
1004 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001005 "IntfId": o.PonPortID,
1006 "SerialNumber": o.Sn(),
1007 }).Error("error-while-processing-start-software-download-request")
1008 }
1009 case omci.DownloadSectionRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001010 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001011 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001012 "OmciMsgType": msg.OmciMsg.MessageType,
1013 "TransCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001014 "EntityInstance": msgObj.EntityInstance,
1015 "SectionNumber": msgObj.SectionNumber,
1016 "SectionData": msgObj.SectionData,
1017 }).Trace("received-download-section-request")
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001018 //Extracting the first 14 bytes to use as a version for this image.
1019 if o.ImageSoftwareReceivedSections == 0 {
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001020 o.InDownloadImageVersion = string(msgObj.SectionData[0:14])
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001021 }
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301022 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
Matteo Scandolocedde462021-03-09 17:37:16 -08001023 o.ImageSoftwareReceivedSections++
1024 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1025 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1026 onuLogger.WithFields(log.Fields{
1027 "OnuId": o.ID,
1028 "IntfId": o.PonPortID,
1029 "OnuSn": o.Sn(),
1030 "Err": err.Error(),
1031 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1032 }
1033 }
1034 }
1035 case omci.DownloadSectionRequestWithResponseType:
1036 // NOTE we only need to respond if an ACK is requested
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301037 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001038 onuLogger.WithFields(log.Fields{
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301039 "OmciMsgType": msg.OmciMsg.MessageType,
1040 "TransCorrId": msg.OmciMsg.TransactionID,
1041 "EntityInstance": msgObj.EntityInstance,
1042 "SectionNumber": msgObj.SectionNumber,
1043 "SectionData": msgObj.SectionData,
1044 }).Trace("received-download-section-request-with-response-type")
1045 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
1046 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1047
1048 if errResp != nil {
1049 onuLogger.WithFields(log.Fields{
1050 "OmciMsgType": msg.OmciMsg.MessageType,
1051 "TransCorrId": msg.OmciMsg.TransactionID,
1052 "Err": errResp.Error(),
1053 "IntfId": o.PonPortID,
1054 "SerialNumber": o.Sn(),
1055 }).Error("error-while-processing-create-download-section-response")
1056 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
1057 }
1058 o.ImageSoftwareReceivedSections++
Matteo Scandolocedde462021-03-09 17:37:16 -08001059 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001060 case omci.EndSoftwareDownloadRequestType:
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001061 success := o.handleEndSoftwareDownloadRequest(msg)
Matteo Scandolocedde462021-03-09 17:37:16 -08001062
Matteo Scandolocedde462021-03-09 17:37:16 -08001063 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001064 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001065 o.MibDataSync++
1066 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1067 onuLogger.WithFields(log.Fields{
1068 "OnuId": o.ID,
1069 "IntfId": o.PonPortID,
1070 "OnuSn": o.Sn(),
1071 "Err": err.Error(),
1072 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1073 }
1074 } else {
1075 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001076 "OmciMsgType": msg.OmciMsg.MessageType,
1077 "TransCorrId": msg.OmciMsg.TransactionID,
1078 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001079 "IntfId": o.PonPortID,
1080 "SerialNumber": o.Sn(),
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001081 }).Error("error-while-responding-to-end-software-download-request")
Matteo Scandolocedde462021-03-09 17:37:16 -08001082 }
1083 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001084 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001085 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1086 onuLogger.WithFields(log.Fields{
1087 "OnuId": o.ID,
1088 "IntfId": o.PonPortID,
1089 "OnuSn": o.Sn(),
1090 "Err": err.Error(),
1091 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1092 }
1093 }
1094 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001095 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001096 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001097 o.MibDataSync++
1098 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1099 onuLogger.WithFields(log.Fields{
1100 "OnuId": o.ID,
1101 "IntfId": o.PonPortID,
1102 "OnuSn": o.Sn(),
1103 "Err": err.Error(),
1104 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1105 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001106 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001107 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001108 previousActiveImage := o.ActiveImageVersion
1109 o.ActiveImageVersion = o.StandbyImageVersion
1110 o.StandbyImageVersion = previousActiveImage
Matteo Scandolocedde462021-03-09 17:37:16 -08001111 } else {
1112 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1113 }
1114 onuLogger.WithFields(log.Fields{
1115 "OnuId": o.ID,
1116 "IntfId": o.PonPortID,
1117 "OnuSn": o.Sn(),
1118 "ActiveImageEntityId": o.ActiveImageEntityId,
1119 "CommittedImageEntityId": o.CommittedImageEntityId,
1120 }).Info("onu-software-image-activated")
1121
1122 // powercycle the ONU
1123 // we run this in a separate goroutine so that
1124 // the ActivateSoftwareResponse is sent to VOLTHA
1125 // NOTE do we need to wait before rebooting?
1126 go func() {
1127 if err := o.Reboot(10 * time.Second); err != nil {
1128 log.WithFields(log.Fields{
1129 "IntfId": o.PonPortID,
1130 "OnuId": o.ID,
1131 "SerialNumber": o.Sn(),
1132 "err": err,
1133 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1134 }
1135 }()
1136 }
1137 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001138 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001139 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001140 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001141 // TODO validate that the image to commit is:
1142 // - active
1143 // - not already committed
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001144 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandolocedde462021-03-09 17:37:16 -08001145 o.CommittedImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001146 //committed becomes standby
1147 o.StandbyImageVersion = o.CommittedImageVersion
1148 o.CommittedImageVersion = o.ActiveImageVersion
Matteo Scandolocedde462021-03-09 17:37:16 -08001149 } else {
1150 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1151 }
1152 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1153 onuLogger.WithFields(log.Fields{
1154 "OnuId": o.ID,
1155 "IntfId": o.PonPortID,
1156 "OnuSn": o.Sn(),
1157 "Err": err.Error(),
1158 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1159 }
1160 onuLogger.WithFields(log.Fields{
1161 "OnuId": o.ID,
1162 "IntfId": o.PonPortID,
1163 "OnuSn": o.Sn(),
1164 "ActiveImageEntityId": o.ActiveImageEntityId,
1165 "CommittedImageEntityId": o.CommittedImageEntityId,
1166 }).Info("onu-software-image-committed")
1167 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301168 case omci.GetAllAlarmsRequestType:
1169 // Reset the alarm sequence number on receiving get all alarms request.
1170 o.onuAlarmsInfoLock.Lock()
1171 for key, alarmInfo := range o.onuAlarmsInfo {
1172 // reset the alarm sequence no
1173 alarmInfo.SequenceNo = 0
1174 o.onuAlarmsInfo[key] = alarmInfo
1175 }
1176 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001177 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301178 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001179 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301180 responsePkt = nil //Do not send any response for error case
1181 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001182 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001183 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001184 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1185 "omciPkt": msg.OmciPkt,
1186 "omciMsgType": msg.OmciMsg.MessageType,
1187 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001188 "IntfId": o.PonPortID,
1189 "SerialNumber": o.Sn(),
1190 }).Warnf("OMCI-message-not-supported")
1191 }
1192
1193 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001194 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001195 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001196 "IntfId": o.PonPortID,
1197 "SerialNumber": o.Sn(),
1198 "omciPacket": responsePkt,
1199 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1200 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001201 }).Errorf("failed-to-send-omci-message: %v", err)
1202 }
1203 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001204
Pragya Arya324337e2020-02-20 14:35:08 +05301205 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001206 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001207}
Pragya Arya324337e2020-02-20 14:35:08 +05301208
Matteo Scandolof9d43412021-01-12 11:11:34 -08001209// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1210func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1211 indication := &openolt.Indication_OmciInd{
1212 OmciInd: &openolt.OmciIndication{
1213 IntfId: o.PonPortID,
1214 OnuId: o.ID,
1215 Pkt: responsePkt,
1216 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001217 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001218 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1219 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001220 }
1221 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001222 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001223 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001224 "omciPacket": indication.OmciInd.Pkt,
1225 "transCorrId": txId,
1226 }).Trace("omci-message-sent")
1227 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001228}
1229
Matteo Scandolo8a574812021-05-20 15:18:53 -07001230// FindUniById retrieves a UNI by ID
1231func (o *Onu) FindUniById(uniID uint32) (*UniPort, error) {
1232 for _, u := range o.UniPorts {
1233 uni := u.(*UniPort)
1234 if uni.ID == uniID {
1235 return uni, nil
1236 }
Matteo Scandolo27428702019-10-11 16:21:16 -07001237 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001238 return nil, fmt.Errorf("cannot-find-uni-with-id-%d-on-onu-%s", uniID, o.Sn())
1239}
1240
1241// FindUniByEntityId retrieves a uni by MeID (the OMCI entity ID)
1242func (o *Onu) FindUniByEntityId(meId uint16) (*UniPort, error) {
1243 entityId := omcilib.EntityID{}.FromUint16(meId)
1244 for _, u := range o.UniPorts {
1245 uni := u.(*UniPort)
1246 if uni.MeId.Equals(entityId) {
1247 return uni, nil
1248 }
1249 }
1250 return nil, fmt.Errorf("cannot-find-uni-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
Matteo Scandolo27428702019-10-11 16:21:16 -07001251}
1252
William Kurkian0418bc82019-11-06 12:16:24 -05001253func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001254 onuLogger.WithFields(log.Fields{
1255 "IntfId": o.PonPortID,
1256 "OnuId": id,
1257 "SerialNumber": o.Sn(),
1258 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001259 o.ID = id
1260}
1261
Matteo Scandolof9d43412021-01-12 11:11:34 -08001262func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001263 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001264 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001265 "Cookie": msg.Flow.Cookie,
1266 "DstPort": msg.Flow.Classifier.DstPort,
1267 "FlowId": msg.Flow.FlowId,
1268 "FlowType": msg.Flow.FlowType,
1269 "GemportId": msg.Flow.GemportId,
1270 "InnerVlan": msg.Flow.Classifier.IVid,
1271 "IntfId": msg.Flow.AccessIntfId,
1272 "IpProto": msg.Flow.Classifier.IpProto,
1273 "OnuId": msg.Flow.OnuId,
1274 "OnuSn": o.Sn(),
1275 "OuterVlan": msg.Flow.Classifier.OVid,
1276 "PortNo": msg.Flow.PortNo,
1277 "SrcPort": msg.Flow.Classifier.SrcPort,
1278 "UniID": msg.Flow.UniId,
1279 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1280 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1281 "ClassifierIVid": msg.Flow.Classifier.IVid,
1282 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001283 "ReplicateFlow": msg.Flow.ReplicateFlow,
1284 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001285 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001286
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001287 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001288
1289 var gemPortId uint32
1290 if msg.Flow.ReplicateFlow {
1291 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1292 // first available gemport (we only need to send one packet)
1293 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1294 gemPortId = msg.Flow.PbitToGemport[0]
1295 } else {
1296 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1297 gemPortId = uint32(msg.Flow.GemportId)
1298 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001299
1300 uni, err := o.FindUniById(uint32(msg.Flow.UniId))
1301 if err != nil {
1302 onuLogger.WithFields(log.Fields{
1303 "IntfId": o.PonPortID,
1304 "OnuId": o.ID,
1305 "UniId": msg.Flow.UniId,
1306 "PortNo": msg.Flow.PortNo,
1307 "SerialNumber": o.Sn(),
1308 "FlowId": msg.Flow.FlowId,
1309 "FlowType": msg.Flow.FlowType,
1310 }).Error("cannot-find-uni-port-for-flow")
1311 }
1312
1313 uni.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
1314 uni.StorePortNo(msg.Flow.PortNo)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001315
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001316 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001317 uni.HandleAuth()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001318 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1319 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001320 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001321 uni.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001322 }
1323}
1324
Matteo Scandolof9d43412021-01-12 11:11:34 -08001325func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001326 onuLogger.WithFields(log.Fields{
1327 "IntfId": o.PonPortID,
1328 "OnuId": o.ID,
1329 "SerialNumber": o.Sn(),
1330 "FlowId": msg.Flow.FlowId,
1331 "FlowType": msg.Flow.FlowType,
1332 }).Debug("ONU receives FlowRemove")
1333
1334 for idx, flow := range o.FlowIds {
1335 // If the gemport is found, delete it from local cache.
1336 if flow == msg.Flow.FlowId {
1337 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1338 break
1339 }
1340 }
1341
1342 if len(o.FlowIds) == 0 {
1343 onuLogger.WithFields(log.Fields{
1344 "IntfId": o.PonPortID,
1345 "OnuId": o.ID,
1346 "SerialNumber": o.Sn(),
1347 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001348
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301349 // check if ONU delete is performed and
1350 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001351 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301352 close(o.Channel)
1353 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001354 }
1355}
1356
Matteo Scandolocedde462021-03-09 17:37:16 -08001357func (o *Onu) Reboot(timeout time.Duration) error {
1358 onuLogger.WithFields(log.Fields{
1359 "IntfId": o.PonPortID,
1360 "OnuId": o.ID,
1361 "SerialNumber": o.Sn(),
1362 }).Debug("shutting-down-onu")
1363 if err := o.HandleShutdownONU(); err != nil {
1364 return err
1365 }
1366 time.Sleep(timeout)
1367 onuLogger.WithFields(log.Fields{
1368 "IntfId": o.PonPortID,
1369 "OnuId": o.ID,
1370 "SerialNumber": o.Sn(),
1371 }).Debug("power-on-onu")
1372 if err := o.HandlePowerOnONU(); err != nil {
1373 return err
1374 }
1375 return nil
1376}
1377
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001378// returns true if the request is successful, false otherwise
1379func (o *Onu) handleEndSoftwareDownloadRequest(msg bbsim.OmciMessage) bool {
1380 msgObj, err := omcilib.ParseEndSoftwareDownloadRequest(msg.OmciPkt)
1381 if err != nil {
1382 onuLogger.WithFields(log.Fields{
1383 "OmciMsgType": msg.OmciMsg.MessageType,
1384 "TransCorrId": msg.OmciMsg.TransactionID,
1385 "Err": err.Error(),
1386 "IntfId": o.PonPortID,
1387 "SerialNumber": o.Sn(),
1388 }).Error("error-while-processing-end-software-download-request")
1389 return false
1390 }
1391
1392 onuLogger.WithFields(log.Fields{
1393 "OnuId": o.ID,
1394 "IntfId": o.PonPortID,
1395 "OnuSn": o.Sn(),
1396 "msgObj": msgObj,
1397 }).Trace("EndSoftwareDownloadRequest received message")
1398
1399 // if the image download is ongoing and we receive a message with
1400 // ImageSize = 0 and Crc = 4294967295 (0xFFFFFFFF) respond with success
1401 if o.ImageSoftwareReceivedSections > 0 &&
1402 msgObj.ImageSize == 0 &&
1403 msgObj.CRC32 == 4294967295 {
1404 o.ImageSoftwareReceivedSections = 0
1405 // NOTE potentially we may want to add a ONU state to reflect
1406 // the software download abort
1407 return true
1408 }
1409
1410 // In the startSoftwareDownload we get the image size and the window size.
1411 // We calculate how many DownloadSection we should receive and validate
1412 // that we got the correct amount when we receive this message
1413 // If the received sections are different from the expected sections
1414 // respond with failure
1415 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1416 onuLogger.WithFields(log.Fields{
1417 "OnuId": o.ID,
1418 "IntfId": o.PonPortID,
1419 "OnuSn": o.Sn(),
1420 "ExpectedSections": o.ImageSoftwareExpectedSections,
1421 "ReceivedSections": o.ImageSoftwareReceivedSections,
1422 }).Errorf("onu-did-not-receive-all-image-sections")
1423 return false
1424 }
1425
1426 // check the received CRC vs the computed CRC
1427 computedCRC := crc32a.Checksum(o.ImageSectionData[:int(msgObj.ImageSize)])
1428 //Convert the crc to network byte order
1429 var byteSlice = make([]byte, 4)
1430 binary.LittleEndian.PutUint32(byteSlice, computedCRC)
1431 computedCRC = binary.BigEndian.Uint32(byteSlice)
1432 if msgObj.CRC32 != computedCRC {
1433 onuLogger.WithFields(log.Fields{
1434 "OnuId": o.ID,
1435 "IntfId": o.PonPortID,
1436 "OnuSn": o.Sn(),
1437 "ReceivedCRC": msgObj.CRC32,
1438 "CalculatedCRC": computedCRC,
1439 }).Errorf("onu-image-crc-validation-failed")
1440 return false
1441 }
1442
1443 o.StandbyImageVersion = o.InDownloadImageVersion
1444 onuLogger.WithFields(log.Fields{
1445 "OnuId": o.ID,
1446 "IntfId": o.PonPortID,
1447 "OnuSn": o.Sn(),
1448 "StandbyVersion": o.StandbyImageVersion,
1449 }).Debug("onu-image-version-updated")
1450 return true
1451}
1452
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001453// BBR methods
1454
1455func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1456 omciMsg := openolt.OmciMsg{
1457 IntfId: intfId,
1458 OnuId: onuId,
1459 Pkt: pktBytes,
1460 }
1461
1462 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1463 log.WithFields(log.Fields{
1464 "IntfId": intfId,
1465 "OnuId": onuId,
1466 "SerialNumber": common.OnuSnToString(sn),
1467 "Pkt": omciMsg.Pkt,
1468 }).Fatalf("Failed to send MIB Reset")
1469 }
1470 log.WithFields(log.Fields{
1471 "IntfId": intfId,
1472 "OnuId": onuId,
1473 "SerialNumber": common.OnuSnToString(sn),
1474 "Pkt": omciMsg.Pkt,
1475 }).Tracef("Sent OMCI message %s", msgType)
1476}
1477
1478func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1479 var next uint16
1480 if len(highPriority) > 0 && highPriority[0] {
1481 next = onu.hpTid
1482 onu.hpTid += 1
1483 if onu.hpTid < 0x8000 {
1484 onu.hpTid = 0x8000
1485 }
1486 } else {
1487 next = onu.tid
1488 onu.tid += 1
1489 if onu.tid >= 0x8000 {
1490 onu.tid = 1
1491 }
1492 }
1493 return next
1494}
1495
1496// TODO move this method in responders/omcisim
Matteo Scandolo8a574812021-05-20 15:18:53 -07001497// StartOmci is called in BBR to start the OMCI state machine
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001498func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1499 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1500 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1501}
1502
Matteo Scandolof9d43412021-01-12 11:11:34 -08001503// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1504func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1505
1506 // we need to encode the packet in HEX
1507 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1508 hex.Encode(pkt, msg.OmciInd.Pkt)
1509 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1510 if err != nil {
1511 log.WithFields(log.Fields{
1512 "IntfId": o.PonPortID,
1513 "SerialNumber": o.Sn(),
1514 "omciPacket": msg.OmciInd.Pkt,
1515 }).Error("BBR Cannot parse OMCI packet")
1516 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001517
1518 log.WithFields(log.Fields{
1519 "IntfId": msg.OmciInd.IntfId,
1520 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001521 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001522 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001523 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301524 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001525 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001526 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001527 log.WithFields(log.Fields{
1528 "IntfId": msg.OmciInd.IntfId,
1529 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001530 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001531 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001532 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001533 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001534 case omci.MibResetResponseType:
1535 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1536 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1537 case omci.MibUploadResponseType:
1538 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1539 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1540 case omci.MibUploadNextResponseType:
1541 o.seqNumber++
Matteo Scandolo8a574812021-05-20 15:18:53 -07001542 // once the mibUpload is complete send a SetRequest for the PPTP to enable the UNI
1543 // NOTE that in BBR we only enable the first UNI
1544 if o.seqNumber == o.MibDb.NumberOfCommands {
1545 meId := omcilib.GenerateUniPortEntityId(1)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001546
Matteo Scandolo8a574812021-05-20 15:18:53 -07001547 meParams := me.ParamData{
1548 EntityID: meId.ToUint16(),
1549 Attributes: me.AttributeValueMap{"AdministrativeState": 0},
1550 }
1551 managedEntity, omciError := me.NewPhysicalPathTerminationPointEthernetUni(meParams)
1552 if omciError.GetError() != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001553 onuLogger.WithFields(log.Fields{
1554 "OnuId": o.ID,
1555 "IntfId": o.PonPortID,
1556 "OnuSn": o.Sn(),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001557 }).Fatal(omciError.GetError())
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001558 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001559
1560 setPPtp, _ := omcilib.CreateSetRequest(managedEntity, 1)
1561 sendOmciMsg(setPPtp, o.PonPortID, o.ID, o.SerialNumber, "setRquest", client)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001562 } else {
1563 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1564 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001565 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001566 case omci.SetResponseType:
1567 // once we set the PPTP to active we can start sending flows
1568
1569 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
1570 onuLogger.WithFields(log.Fields{
1571 "OnuId": o.ID,
1572 "IntfId": o.PonPortID,
1573 "OnuSn": o.Sn(),
1574 }).Errorf("Error while transitioning ONU State %v", err)
1575 }
1576 case omci.AlarmNotificationType:
1577 log.Info("bbr-received-alarm")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001578 }
1579}
1580
1581func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1582
1583 classifierProto := openolt.Classifier{
1584 EthType: uint32(layers.EthernetTypeEAPOL),
1585 OVid: 4091,
1586 }
1587
1588 actionProto := openolt.Action{}
1589
1590 downstreamFlow := openolt.Flow{
1591 AccessIntfId: int32(o.PonPortID),
1592 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001593 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001594 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001595 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001596 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001597 Classifier: &classifierProto,
1598 Action: &actionProto,
1599 Priority: int32(100),
1600 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001601 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1602 // AllocId and GemPorts need to be unique per PON
1603 // for now use the ONU-ID, will need to change once we support multiple UNIs
1604 AllocId: int32(o.ID),
1605 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001606 }
1607
1608 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1609 log.WithFields(log.Fields{
1610 "IntfId": o.PonPortID,
1611 "OnuId": o.ID,
1612 "FlowId": downstreamFlow.FlowId,
1613 "PortNo": downstreamFlow.PortNo,
1614 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001615 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001616 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001617 }
1618 log.WithFields(log.Fields{
1619 "IntfId": o.PonPortID,
1620 "OnuId": o.ID,
1621 "FlowId": downstreamFlow.FlowId,
1622 "PortNo": downstreamFlow.PortNo,
1623 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1624 }).Info("Sent EAPOL Flow")
1625}
1626
1627func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001628
Matteo Scandolo8a574812021-05-20 15:18:53 -07001629 // BBR only works with a single UNI and a single service (ATT HSIA)
1630 hsia := o.UniPorts[0].(*UniPort).Services[0].(*Service)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001631 classifierProto := openolt.Classifier{
1632 EthType: uint32(layers.EthernetTypeIPv4),
1633 SrcPort: uint32(68),
1634 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001635 OVid: uint32(hsia.CTag),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001636 OPbits: 255,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001637 }
1638
1639 actionProto := openolt.Action{}
1640
1641 downstreamFlow := openolt.Flow{
1642 AccessIntfId: int32(o.PonPortID),
1643 OnuId: int32(o.ID),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001644 UniId: int32(0), // BBR only supports a single UNI
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001645 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001646 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001647 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001648 Classifier: &classifierProto,
1649 Action: &actionProto,
1650 Priority: int32(100),
1651 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001652 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1653 // AllocId and GemPorts need to be unique per PON
1654 // for now use the ONU-ID, will need to change once we support multiple UNIs
1655 AllocId: int32(o.ID),
1656 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001657 }
1658
1659 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1660 log.WithFields(log.Fields{
1661 "IntfId": o.PonPortID,
1662 "OnuId": o.ID,
1663 "FlowId": downstreamFlow.FlowId,
1664 "PortNo": downstreamFlow.PortNo,
1665 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001666 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001667 }).Fatalf("Failed to send DHCP Flow")
1668 }
1669 log.WithFields(log.Fields{
1670 "IntfId": o.PonPortID,
1671 "OnuId": o.ID,
1672 "FlowId": downstreamFlow.FlowId,
1673 "PortNo": downstreamFlow.PortNo,
1674 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1675 }).Info("Sent DHCP Flow")
1676}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301677
1678// DeleteFlow method search and delete flowKey from the onu flows slice
1679func (onu *Onu) DeleteFlow(key FlowKey) {
1680 for pos, flowKey := range onu.Flows {
1681 if flowKey == key {
1682 // delete the flowKey by shifting all flowKeys by one
1683 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1684 t := make([]FlowKey, len(onu.Flows))
1685 copy(t, onu.Flows)
1686 onu.Flows = t
1687 break
1688 }
1689 }
1690}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301691
1692func (onu *Onu) ReDiscoverOnu() {
1693 // Wait for few seconds to be sure of the cleanup
1694 time.Sleep(5 * time.Second)
1695
1696 onuLogger.WithFields(log.Fields{
1697 "IntfId": onu.PonPortID,
1698 "OnuId": onu.ID,
1699 "OnuSn": onu.Sn(),
1700 }).Debug("Send ONU Re-Discovery")
1701
1702 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001703 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301704 log.WithFields(log.Fields{
1705 "IntfId": onu.PonPortID,
1706 "OnuSn": onu.Sn(),
1707 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001708 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301709 }
1710
Matteo Scandolocedde462021-03-09 17:37:16 -08001711 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301712 log.WithFields(log.Fields{
1713 "IntfId": onu.PonPortID,
1714 "OnuSn": onu.Sn(),
1715 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001716 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301717 }
1718}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001719
Matteo Scandolo8a574812021-05-20 15:18:53 -07001720// deprecated, delegate this to the uniPort
Matteo Scandolo4a036262020-08-17 15:56:13 -07001721func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001722 // FIXME is there a better way to avoid this loop?
1723 for _, u := range onu.UniPorts {
1724 uni := u.(*UniPort)
1725 for _, s := range uni.Services {
1726 service := s.(*Service)
1727 if service.HwAddress.String() == macAddress.String() {
1728 return service, nil
1729 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001730 }
1731 }
1732 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1733}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301734
Matteo Scandolo8a574812021-05-20 15:18:53 -07001735func (onu *Onu) findUniByPortNo(portNo uint32) (*UniPort, error) {
1736 for _, u := range onu.UniPorts {
1737 uni := u.(*UniPort)
1738 if uni.PortNo == portNo {
1739 return uni, nil
1740 }
1741 }
1742 return nil, fmt.Errorf("cannot-find-uni-with-port-no-%d", portNo)
1743}
1744
Himani Chawla13b1ee02021-03-15 01:43:53 +05301745func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1746 switch alarmType {
1747 case "ONU_ALARM_LOS":
1748 msg := bbsim.Message{
1749 Type: bbsim.UniStatusAlarm,
1750 Data: bbsim.UniStatusAlarmMessage{
1751 OnuSN: o.SerialNumber,
1752 OnuID: o.ID,
1753 EntityID: 257,
1754 RaiseOMCIAlarm: raiseOMCIAlarm,
1755 },
1756 }
1757 o.Channel <- msg
1758 }
1759
1760}
1761
1762func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1763 o.onuAlarmsInfoLock.Lock()
1764 defer o.onuAlarmsInfoLock.Unlock()
1765 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1766 if alarmInfo.SequenceNo == 255 {
1767 alarmInfo.SequenceNo = 1
1768 } else {
1769 alarmInfo.SequenceNo++
1770 }
1771 o.onuAlarmsInfo[key] = alarmInfo
1772 return alarmInfo.SequenceNo
1773 } else {
1774 // This is the first time alarm notification message is being sent
1775 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1776 SequenceNo: 1,
1777 }
1778 return 1
1779 }
1780}