blob: f7d21719f67160f26e56d8df388e2d5b4d8b2bc1 [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"
Elia Battistonfe017662022-01-05 11:43:16 +010024 "math/rand"
Mahir Gunyela1753ae2021-06-23 00:24:56 -070025 "sync"
26
Matteo Scandolo8a574812021-05-20 15:18:53 -070027 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
28 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
29 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000030
Matteo Scandolof9d43412021-01-12 11:11:34 -080031 pb "github.com/opencord/bbsim/api/bbsim"
32 "github.com/opencord/bbsim/internal/bbsim/alarmsim"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000033
34 "net"
35 "strconv"
36 "time"
Himani Chawla13b1ee02021-03-15 01:43:53 +053037
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080038 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Andrea Campanella10426e22021-10-15 17:58:04 +020039 me "github.com/opencord/omci-lib-go/v2/generated"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010040
Himani Chawla4ff5fab2021-11-09 19:19:29 +053041 "github.com/boguslaw-wojcik/crc32a"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070042 "github.com/google/gopacket/layers"
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070043 "github.com/jpillora/backoff"
Matteo Scandolo4747d292019-08-05 11:50:18 -070044 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070045 "github.com/opencord/bbsim/internal/common"
46 omcilib "github.com/opencord/bbsim/internal/common/omci"
Andrea Campanella10426e22021-10-15 17:58:04 +020047 "github.com/opencord/omci-lib-go/v2"
David K. Bainbridgec415efe2021-08-19 13:05:21 +000048 "github.com/opencord/voltha-protos/v5/go/openolt"
49 "github.com/opencord/voltha-protos/v5/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070050 log "github.com/sirupsen/logrus"
51)
52
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070053var onuLogger = log.WithFields(log.Fields{
54 "module": "ONU",
55})
56
Matteo Scandolocedde462021-03-09 17:37:16 -080057const (
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000058 maxOmciMsgCounter = 10
59)
60
61const (
Matteo Scandolocedde462021-03-09 17:37:16 -080062 // ONU transitions
63 OnuTxInitialize = "initialize"
64 OnuTxDiscover = "discover"
65 OnuTxEnable = "enable"
66 OnuTxDisable = "disable"
67 OnuTxPonDisable = "pon_disable"
68 OnuTxStartImageDownload = "start_image_download"
69 OnuTxProgressImageDownload = "progress_image_download"
70 OnuTxCompleteImageDownload = "complete_image_download"
71 OnuTxFailImageDownload = "fail_image_download"
72 OnuTxActivateImage = "activate_image"
73 OnuTxCommitImage = "commit_image"
74
75 // ONU States
76 OnuStateCreated = "created"
77 OnuStateInitialized = "initialized"
78 OnuStateDiscovered = "discovered"
79 OnuStateEnabled = "enabled"
80 OnuStateDisabled = "disabled"
81 OnuStatePonDisabled = "pon_disabled"
82 OnuStateImageDownloadStarted = "image_download_started"
83 OnuStateImageDownloadInProgress = "image_download_in_progress"
84 OnuStateImageDownloadComplete = "image_download_completed"
85 OnuStateImageDownloadError = "image_download_error"
86 OnuStateImageActivated = "software_image_activated"
87 OnuStateImageCommitted = "software_image_committed"
88
89 // BBR ONU States and Transitions
90 BbrOnuTxSendEapolFlow = "send_eapol_flow"
91 BbrOnuStateEapolFlowSent = "eapol_flow_sent"
92 BbrOnuTxSendDhcpFlow = "send_dhcp_flow"
93 BbrOnuStateDhcpFlowSent = "dhcp_flow_sent"
94)
95
Andrea Campanellacc9b1662022-01-26 17:47:48 +010096type FlowKey struct {
yasin saplic07b9522022-01-27 11:23:54 +000097 ID uint64
Andrea Campanellacc9b1662022-01-26 17:47:48 +010098}
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
Elia Battistonac63b112022-01-12 18:40:49 +0100110 UniPorts []UniPortIf
111 PotsPorts []PotsPortIf
Andrea Campanellacc9b1662022-01-26 17:47:48 +0100112 Flows []FlowKey
Elia Battistonac63b112022-01-12 18:40:49 +0100113 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700114
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700115 OperState *fsm.FSM
116 SerialNumber *openolt.SerialNumber
117
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700118 AdminLockState uint8 // 0 is enabled, 1 is disabled.
119
Matteo Scandolof9d43412021-01-12 11:11:34 -0800120 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700121
122 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800123 MibDataSync uint8
124 ImageSoftwareExpectedSections int
125 ImageSoftwareReceivedSections int
126 ActiveImageEntityId uint16
127 CommittedImageEntityId uint16
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700128 StandbyImageVersion string
129 ActiveImageVersion string
Matteo Scandolo76f6b892021-11-15 16:13:06 -0800130 InDownloadImageVersion string
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700131 CommittedImageVersion string
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000132 OmciResponseRate uint8
133 OmciMsgCounter uint8
Himani Chawla4ff5fab2021-11-09 19:19:29 +0530134 ImageSectionData []byte
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800135
136 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700137 tid uint16
138 hpTid uint16
139 seqNumber uint16
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700140 MibDb *omcilib.MibDb
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700141
Anand S Katti09541352020-01-29 15:54:01 +0530142 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
143 TrafficSchedulers *tech_profile.TrafficSchedulers
Himani Chawla13b1ee02021-03-15 01:43:53 +0530144 onuAlarmsInfoLock sync.RWMutex
145 onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700146}
147
Matteo Scandolo99f18462019-10-28 14:14:28 -0700148func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700149 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700150}
151
Matteo Scandolo8a574812021-05-20 15:18:53 -0700152func 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 -0700153
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700154 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800155 ID: id,
156 PonPortID: pon.ID,
157 PonPort: pon,
Matteo Scandolocedde462021-03-09 17:37:16 -0800158 tid: 0x1,
159 hpTid: 0x8000,
160 seqNumber: 0,
161 DoneChannel: make(chan bool, 1),
162 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
Andrea Campanellacc9b1662022-01-26 17:47:48 +0100163 Flows: []FlowKey{},
Matteo Scandolocedde462021-03-09 17:37:16 -0800164 DiscoveryDelay: delay,
165 MibDataSync: 0,
166 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
167 ImageSoftwareReceivedSections: 0,
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700168 //TODO this needs reworking, it's always 0 or 1, possibly base all on the version
169 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
170 CommittedImageEntityId: 0,
171 StandbyImageVersion: "BBSM_IMG_00000",
172 ActiveImageVersion: "BBSM_IMG_00001",
173 CommittedImageVersion: "BBSM_IMG_00001",
174 OmciResponseRate: olt.OmciResponseRate,
175 OmciMsgCounter: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700176 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800177 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700178 // NOTE this state machine is used to track the operational
179 // state as requested by VOLTHA
180 o.OperState = getOperStateFSM(func(e *fsm.Event) {
181 onuLogger.WithFields(log.Fields{
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700182 "OnuId": o.ID,
183 "IntfId": o.PonPortID,
184 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700185 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
186 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530187 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700188 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
189 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800190 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700191 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700192 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800193 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
194 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
195 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100196 // 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 -0800197 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530198 // 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 +0200199 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted, OnuStateImageDownloadComplete}, Dst: OnuStatePonDisabled},
Matteo Scandolocedde462021-03-09 17:37:16 -0800200 // Software Image Download related states
Matteo Scandolo9f4bf4f2021-06-22 09:41:02 +0200201 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateImageDownloadStarted},
Matteo Scandolocedde462021-03-09 17:37:16 -0800202 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
203 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
204 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
205 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
206 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700207 // BBR States
208 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800209 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
210 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700211 },
212 fsm.Callbacks{
213 "enter_state": func(e *fsm.Event) {
214 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700215 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700216 fmt.Sprintf("enter_%s", OnuStateInitialized): func(e *fsm.Event) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100217 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800218 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800219
Matteo Scandolocedde462021-03-09 17:37:16 -0800220 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800221 onuLogger.WithFields(log.Fields{
222 "OnuId": o.ID,
223 "IntfId": o.PonPortID,
224 "OnuSn": o.Sn(),
225 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
226 }
227
Pragya Arya1cbefa42020-01-13 12:15:29 +0530228 if !isMock {
229 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700230 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530231 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100232 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700233 fmt.Sprintf("enter_%s", OnuStateDiscovered): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800234 msg := bbsim.Message{
235 Type: bbsim.OnuDiscIndication,
236 Data: bbsim.OnuDiscIndicationMessage{
237 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100238 },
239 }
240 o.Channel <- msg
241 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700242 fmt.Sprintf("enter_%s", OnuStateEnabled): func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800243
244 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
245 onuLogger.WithFields(log.Fields{
246 "IntfId": o.PonPortID,
247 "OnuId": o.ID,
248 "SerialNumber": o.Sn(),
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700249 }).Errorf("onu-id-duplicated-with-%s", common.OnuSnToString(sn))
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800250 return
251 } else {
252 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
253 }
254
Matteo Scandolof9d43412021-01-12 11:11:34 -0800255 msg := bbsim.Message{
256 Type: bbsim.OnuIndication,
257 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700258 OnuSN: o.SerialNumber,
259 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800260 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700261 },
262 }
263 o.Channel <- msg
264 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700265 fmt.Sprintf("enter_%s", OnuStateDisabled): func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700266
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700267 o.cleanupOnuState()
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700268
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700269 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800270 if err := o.OperState.Event("disable"); err != nil {
271 onuLogger.WithFields(log.Fields{
272 "OnuId": o.ID,
273 "IntfId": o.PonPortID,
274 "OnuSn": o.Sn(),
275 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
276 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700277 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800278 msg := bbsim.Message{
279 Type: bbsim.OnuIndication,
280 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700281 OnuSN: o.SerialNumber,
282 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800283 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700284 },
285 }
286 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530287
Matteo Scandolo8a574812021-05-20 15:18:53 -0700288 // disable the UNI ports
289 for _, uni := range o.UniPorts {
290 _ = uni.Disable()
291 }
292
Elia Battistonac63b112022-01-12 18:40:49 +0100293 // disable the POTS UNI ports
294 for _, pots := range o.PotsPorts {
295 _ = pots.Disable()
296 }
297
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530298 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100299 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolo8a574812021-05-20 15:18:53 -0700300 // NOTE may need to wait for the UNIs to be down too before shutting down the channel
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530301 if len(o.FlowIds) == 0 {
302 close(o.Channel)
303 }
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700304 },
305 fmt.Sprintf("enter_%s", OnuStatePonDisabled): func(event *fsm.Event) {
306 o.cleanupOnuState()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700307 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700308 // BBR states
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700309 fmt.Sprintf("enter_%s", BbrOnuStateEapolFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800310 msg := bbsim.Message{
311 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700312 }
313 o.Channel <- msg
314 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700315 fmt.Sprintf("enter_%s", BbrOnuStateDhcpFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800316 msg := bbsim.Message{
317 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700318 }
319 o.Channel <- msg
320 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700321 },
322 )
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700323 onuLogger.WithFields(log.Fields{
Elia Battistonac63b112022-01-12 18:40:49 +0100324 "OnuId": o.ID,
325 "IntfId": o.PonPortID,
326 "OnuSn": o.Sn(),
327 "NumUni": olt.NumUni,
328 "NumPots": olt.NumPots,
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700329 }).Debug("creating-uni-ports")
Elia Battistonac63b112022-01-12 18:40:49 +0100330
331 // create Ethernet UNIs
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700332 for i := 0; i < olt.NumUni; i++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700333 uni, err := NewUniPort(uint32(i), &o, nextCtag, nextStag)
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700334 if err != nil {
335 onuLogger.WithFields(log.Fields{
336 "OnuId": o.ID,
337 "IntfId": o.PonPortID,
338 "OnuSn": o.Sn(),
339 "Err": err,
340 }).Fatal("cannot-create-uni-port")
341 }
342 o.UniPorts = append(o.UniPorts, uni)
343 }
Elia Battistonac63b112022-01-12 18:40:49 +0100344 // create POTS UNIs, with progressive IDs
345 for i := olt.NumUni; i < (olt.NumUni + olt.NumPots); i++ {
346 pots, err := NewPotsPort(uint32(i), &o)
347 if err != nil {
348 onuLogger.WithFields(log.Fields{
349 "OnuId": o.ID,
350 "IntfId": o.PonPortID,
351 "OnuSn": o.Sn(),
352 "Err": err,
353 }).Fatal("cannot-create-pots-port")
354 }
355 o.PotsPorts = append(o.PotsPorts, pots)
356 }
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700357
Elia Battistonac63b112022-01-12 18:40:49 +0100358 mibDb, err := omcilib.GenerateMibDatabase(len(o.UniPorts), len(o.PotsPorts))
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700359 if err != nil {
360 onuLogger.WithFields(log.Fields{
361 "OnuId": o.ID,
362 "IntfId": o.PonPortID,
363 "OnuSn": o.Sn(),
364 }).Fatal("cannot-generate-mibdb-for-onu")
365 }
366 o.MibDb = mibDb
367
Matteo Scandolo27428702019-10-11 16:21:16 -0700368 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700369}
370
William Kurkian0418bc82019-11-06 12:16:24 -0500371func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700372 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700373 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700374 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700375 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700376 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
377}
378
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700379// cleanupOnuState this method is to clean the local state when the ONU is disabled
380func (o *Onu) cleanupOnuState() {
381 // clean the ONU state
Andrea Campanellacc9b1662022-01-26 17:47:48 +0100382 o.Flows = []FlowKey{}
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700383 o.PonPort.removeOnuId(o.ID)
384 o.PonPort.removeAllocId(o.SerialNumber)
385 o.PonPort.removeGemPortBySn(o.SerialNumber)
386
387 o.onuAlarmsInfoLock.Lock()
388 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
389 o.onuAlarmsInfoLock.Unlock()
390}
391
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100392// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000393func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700394 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100395 "onuID": o.ID,
396 "onuSN": o.Sn(),
397 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700398 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100399 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700400
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700401 defer onuLogger.WithFields(log.Fields{
402 "onuID": o.ID,
403 "onuSN": o.Sn(),
404 "stream": stream,
405 }).Debug("Stopped handling ONU Indication Channel")
406
David Bainbridge103cf022019-12-16 20:11:35 +0000407loop:
408 for {
409 select {
410 case <-ctx.Done():
411 onuLogger.WithFields(log.Fields{
412 "onuID": o.ID,
413 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700414 }).Debug("ONU message handling canceled via context")
415 break loop
416 case <-stream.Context().Done():
417 onuLogger.WithFields(log.Fields{
418 "onuID": o.ID,
419 "onuSN": o.Sn(),
420 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000421 break loop
422 case message, ok := <-o.Channel:
423 if !ok || ctx.Err() != nil {
424 onuLogger.WithFields(log.Fields{
425 "onuID": o.ID,
426 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700427 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000428 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700429 }
David Bainbridge103cf022019-12-16 20:11:35 +0000430 onuLogger.WithFields(log.Fields{
431 "onuID": o.ID,
432 "onuSN": o.Sn(),
433 "messageType": message.Type,
434 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700435
David Bainbridge103cf022019-12-16 20:11:35 +0000436 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800437 case bbsim.OnuDiscIndication:
438 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000439 // 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 +0530440 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000441 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800442 case bbsim.OnuIndication:
443 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000444 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800445 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800446 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800447 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200448 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800449 case bbsim.UniStatusAlarm:
450 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530451 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
452 MeInstance: msg.EntityID,
453 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
454 }
455 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
456 o.onuAlarmsInfoLock.Lock()
457 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
458 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
459 if pkt != nil { //pkt will be nil if we are unable to create the alarm
460 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
461 onuLogger.WithFields(log.Fields{
462 "IntfId": o.PonPortID,
463 "SerialNumber": o.Sn(),
464 "omciPacket": pkt,
465 "adminState": msg.AdminState,
466 "entityID": msg.EntityID,
467 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
468 alarmInfo.SequenceNo--
469 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800470 onuLogger.WithFields(log.Fields{
471 "IntfId": o.PonPortID,
472 "SerialNumber": o.Sn(),
473 "omciPacket": pkt,
474 "adminState": msg.AdminState,
475 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530476 }).Trace("UNI-Link-alarm-sent")
477 if alarmBitMap == [28]byte{0} {
478 delete(o.onuAlarmsInfo, onuAlarmMapKey)
479 } else {
480 alarmInfo.AlarmBitMap = alarmBitMap
481 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
482 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800483 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530484 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800485 case bbsim.FlowAdd:
486 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700487 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800488 case bbsim.FlowRemoved:
489 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700490 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800491 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700492
Matteo Scandolof9d43412021-01-12 11:11:34 -0800493 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000494
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700495 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000496 "IntfId": msg.IntfId,
497 "OnuId": msg.OnuId,
498 "pktType": msg.Type,
499 }).Trace("Received OnuPacketOut Message")
500
Matteo Scandolo8a574812021-05-20 15:18:53 -0700501 uni, err := o.findUniByPortNo(msg.PortNo)
Matteo Scandolo618a6582020-09-09 12:21:29 -0700502
Matteo Scandolo8a574812021-05-20 15:18:53 -0700503 if err != nil {
504 onuLogger.WithFields(log.Fields{
505 "IntfId": msg.IntfId,
506 "OnuId": msg.OnuId,
507 "pktType": msg.Type,
508 "portNo": msg.PortNo,
509 "MacAddress": msg.MacAddress,
510 "Pkt": hex.EncodeToString(msg.Packet.Data()),
511 "OnuSn": o.Sn(),
512 }).Error("Cannot find Uni associated with packet")
513 return
David Bainbridge103cf022019-12-16 20:11:35 +0000514 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700515 uni.PacketCh <- msg
516 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800517 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000518 // NOTE we only receive BBR packets here.
519 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
520 // 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 -0800521 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000522
Matteo Scandolo8a574812021-05-20 15:18:53 -0700523 onuLogger.WithFields(log.Fields{
524 "IntfId": msg.IntfId,
525 "OnuId": msg.OnuId,
526 "PortNo": msg.PortNo,
527 "GemPortId": msg.GemPortId,
528 "pktType": msg.Type,
David Bainbridge103cf022019-12-16 20:11:35 +0000529 }).Trace("Received OnuPacketIn Message")
530
Matteo Scandolo8a574812021-05-20 15:18:53 -0700531 uni, err := o.findUniByPortNo(msg.PortNo)
532 if err != nil {
533 onuLogger.WithFields(log.Fields{
534 "IntfId": msg.IntfId,
535 "OnuId": msg.OnuId,
536 "PortNo": msg.PortNo,
537 "GemPortId": msg.GemPortId,
538 "pktType": msg.Type,
539 }).Error(err.Error())
540 }
541
542 // BBR has one service and one UNI
543 serviceId := uint32(0)
544 oltId := 0
David Bainbridge103cf022019-12-16 20:11:35 +0000545 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700546 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 +0000547 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700548 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000549 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800550 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800551 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800552 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
553 o.handleOmciResponse(msg, client)
554 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000555 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800556 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000557 o.sendDhcpFlow(client)
558 default:
559 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700560 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700561 }
562 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700563}
564
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800565func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700566 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700567 sn.VendorId = []byte("BBSM")
568 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700569 return sn
570}
571
Matteo Scandolof9d43412021-01-12 11:11:34 -0800572func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700573 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800574 IntfId: o.PonPortID,
575 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700576 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700577
Matteo Scandolo4747d292019-08-05 11:50:18 -0700578 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700579 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700580 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700581 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700582
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700583 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800584 "IntfId": o.PonPortID,
585 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700586 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700587 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800588 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800589
590 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
591 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800592 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800593 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800594 o.sendOnuDiscIndication(msg, stream)
595 }
596 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700597}
598
Matteo Scandolof9d43412021-01-12 11:11:34 -0800599func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800600 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
601 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700602
603 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700604 IntfId: o.PonPortID,
605 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700606 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700607 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700608 SerialNumber: o.SerialNumber,
609 }}
610 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800611 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700612 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700613 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700614 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700615 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800616 "IntfId": o.PonPortID,
617 "OnuId": o.ID,
618 "VolthaOnuId": msg.OnuID,
619 "OperState": msg.OperState.String(),
620 "AdminState": msg.OperState.String(),
621 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700622 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700623
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700624}
625
Matteo Scandolof9d43412021-01-12 11:11:34 -0800626func (o *Onu) HandleShutdownONU() error {
627
628 dyingGasp := pb.ONUAlarmRequest{
629 AlarmType: "DYING_GASP",
630 SerialNumber: o.Sn(),
631 Status: "on",
632 }
633
634 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
635 onuLogger.WithFields(log.Fields{
636 "OnuId": o.ID,
637 "IntfId": o.PonPortID,
638 "OnuSn": o.Sn(),
639 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
640 return err
641 }
642
643 losReq := pb.ONUAlarmRequest{
644 AlarmType: "ONU_ALARM_LOS",
645 SerialNumber: o.Sn(),
646 Status: "on",
647 }
648
649 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
650 onuLogger.WithFields(log.Fields{
651 "OnuId": o.ID,
652 "IntfId": o.PonPortID,
653 "OnuSn": o.Sn(),
654 }).Errorf("Cannot send LOS: %s", err.Error())
655
656 return err
657 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530658 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800659 // TODO if it's the last ONU on the PON, then send a PON LOS
660
Matteo Scandolocedde462021-03-09 17:37:16 -0800661 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800662 onuLogger.WithFields(log.Fields{
663 "OnuId": o.ID,
664 "IntfId": o.PonPortID,
665 "OnuSn": o.Sn(),
666 }).Errorf("Cannot shutdown ONU: %s", err.Error())
667 return err
668 }
669
670 return nil
671}
672
673func (o *Onu) HandlePowerOnONU() error {
674 intitalState := o.InternalState.Current()
675
676 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800677 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
678 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800679 onuLogger.WithFields(log.Fields{
680 "OnuId": o.ID,
681 "IntfId": o.PonPortID,
682 "OnuSn": o.Sn(),
683 }).Errorf("Cannot poweron ONU: %s", err.Error())
684 return err
685 }
686 }
687
688 // turn off the LOS Alarm
689 losReq := pb.ONUAlarmRequest{
690 AlarmType: "ONU_ALARM_LOS",
691 SerialNumber: o.Sn(),
692 Status: "off",
693 }
694
695 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
696 onuLogger.WithFields(log.Fields{
697 "OnuId": o.ID,
698 "IntfId": o.PonPortID,
699 "OnuSn": o.Sn(),
700 }).Errorf("Cannot send LOS: %s", err.Error())
701 return err
702 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530703 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800704
705 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800706 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800707 onuLogger.WithFields(log.Fields{
708 "OnuId": o.ID,
709 "IntfId": o.PonPortID,
710 "OnuSn": o.Sn(),
711 }).Errorf("Cannot poweron ONU: %s", err.Error())
712 return err
713 }
714
715 // move o directly to enable state only when its a powercycle case
716 // in case of first time o poweron o will be moved to enable on
717 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800718 if intitalState == OnuStateDisabled {
719 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800720 onuLogger.WithFields(log.Fields{
721 "OnuId": o.ID,
722 "IntfId": o.PonPortID,
723 "OnuSn": o.Sn(),
724 }).Errorf("Cannot enable ONU: %s", err.Error())
725 return err
726 }
727 }
728
729 return nil
730}
731
732func (o *Onu) SetAlarm(alarmType string, status string) error {
733 alarmReq := pb.ONUAlarmRequest{
734 AlarmType: alarmType,
735 SerialNumber: o.Sn(),
736 Status: status,
737 }
738
739 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
740 if err != nil {
741 return err
742 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530743 raiseAlarm := false
744 if alarmReq.Status == "on" {
745 raiseAlarm = true
746 }
747 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800748 return nil
749}
750
751func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530752 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700753 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530754 if err != nil {
755 log.Errorf("error in getting msgType %v", err)
756 return
757 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800758 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530759 o.seqNumber = 0
760 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800761 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530762 o.seqNumber++
763 if o.seqNumber > 290 {
764 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
765 }
766 }
767 }
768}
769
Matteo Scandolof9d43412021-01-12 11:11:34 -0800770// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
771// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200772func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800773
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700774 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700775 "omciMsgType": msg.OmciMsg.MessageType,
776 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
777 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700778 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700779 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800780 }).Trace("omci-message-decoded")
781
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000782 if o.OmciMsgCounter < maxOmciMsgCounter {
783 o.OmciMsgCounter++
784 } else {
785 o.OmciMsgCounter = 1
786 }
787 if o.OmciMsgCounter > o.OmciResponseRate {
788 onuLogger.WithFields(log.Fields{
789 "OmciMsgCounter": o.OmciMsgCounter,
790 "OmciResponseRate": o.OmciResponseRate,
791 "omciMsgType": msg.OmciMsg.MessageType,
Matteo Scandoloa96e2242021-09-28 10:13:17 -0700792 "txId": msg.OmciMsg.TransactionID,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200793 }).Debug("skipping-omci-msg-response")
794 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000795 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800796 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800797 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700798 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800799 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800800 onuLogger.WithFields(log.Fields{
801 "IntfId": o.PonPortID,
802 "OnuId": o.ID,
803 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700804 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700805 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800806 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700807
808 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
809 o.PonPort.removeAllocId(o.SerialNumber)
810 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800811 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800812 case omci.MibUploadRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700813 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800814 case omci.MibUploadNextRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700815 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800816 case omci.GetRequestType:
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700817 onuDown := o.AdminLockState == 1
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700818 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId,
819 o.CommittedImageEntityId, o.StandbyImageVersion, o.ActiveImageVersion, o.CommittedImageVersion, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800820 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800821 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700822 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800823 switch msgObj.EntityClass {
824 case me.PhysicalPathTerminationPointEthernetUniClassID:
825 // if we're Setting a PPTP state
Matteo Scandolo8a574812021-05-20 15:18:53 -0700826 // we need to send the appropriate alarm (handled in the UNI struct)
827 uni, err := o.FindUniByEntityId(msgObj.EntityInstance)
828 if err != nil {
829 onuLogger.Error(err)
830 success = false
831 } else {
832 // 1 locks the UNI, 0 unlocks it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800833 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700834 var err error
Himani Chawla13b1ee02021-03-15 01:43:53 +0530835 if adminState == 1 {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700836 err = uni.Disable()
Girish Gowdra996d81e2021-04-21 16:16:27 -0700837 } else {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700838 err = uni.Enable()
Himani Chawla13b1ee02021-03-15 01:43:53 +0530839 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700840 if err != nil {
841 onuLogger.WithFields(log.Fields{
842 "IntfId": o.PonPortID,
843 "OnuId": o.ID,
844 "UniMeId": uni.MeId,
845 "UniId": uni.ID,
846 "SerialNumber": o.Sn(),
847 "Err": err.Error(),
848 }).Warn("cannot-change-uni-status")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800849 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800850 }
Elia Battistonac63b112022-01-12 18:40:49 +0100851 case me.PhysicalPathTerminationPointPotsUniClassID:
852 // if we're Setting a PPTP state
853 // we need to send the appropriate alarm (handled in the POTS struct)
854 pots, err := o.FindPotsByEntityId(msgObj.EntityInstance)
855 if err != nil {
856 onuLogger.Error(err)
857 success = false
858 } else {
859 // 1 locks the UNI, 0 unlocks it
860 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
861 var err error
862 if adminState == 1 {
863 err = pots.Disable()
864 } else {
865 err = pots.Enable()
866 }
867 if err != nil {
868 onuLogger.WithFields(log.Fields{
869 "IntfId": o.PonPortID,
870 "OnuId": o.ID,
871 "PotsMeId": pots.MeId,
872 "PotsId": pots.ID,
873 "SerialNumber": o.Sn(),
874 "Err": err.Error(),
875 }).Warn("cannot-change-pots-status")
876 }
877 }
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700878 case me.OnuGClassID:
879 o.AdminLockState = msgObj.Attributes["AdministrativeState"].(uint8)
880 onuLogger.WithFields(log.Fields{
881 "IntfId": o.PonPortID,
882 "OnuId": o.ID,
883 "SerialNumber": o.Sn(),
884 "AdminLockState": o.AdminLockState,
885 }).Debug("set-onu-admin-lock-state")
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800886 case me.TContClassID:
887 allocId := msgObj.Attributes["AllocId"].(uint16)
888
889 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
890 // otherwise we are adding it
891 if allocId == 255 || allocId == 65535 {
892 onuLogger.WithFields(log.Fields{
893 "IntfId": o.PonPortID,
894 "OnuId": o.ID,
895 "TContId": msgObj.EntityInstance,
896 "AllocId": allocId,
897 "SerialNumber": o.Sn(),
898 }).Trace("freeing-alloc-id-via-omci")
899 o.PonPort.removeAllocId(o.SerialNumber)
900 } else {
901 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
902 onuLogger.WithFields(log.Fields{
903 "IntfId": o.PonPortID,
904 "OnuId": o.ID,
905 "AllocId": allocId,
906 "SerialNumber": o.Sn(),
907 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
908 success = false
909 } else {
910 onuLogger.WithFields(log.Fields{
911 "IntfId": o.PonPortID,
912 "OnuId": o.ID,
913 "TContId": msgObj.EntityInstance,
914 "AllocId": allocId,
915 "SerialNumber": o.Sn(),
916 }).Trace("storing-alloc-id-via-omci")
917 o.PonPort.storeAllocId(allocId, o.SerialNumber)
918 }
919 }
920
921 }
922
923 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700924 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800925 o.MibDataSync++
926 }
927 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700928 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800929 }
930 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800931 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
932 var used bool
933 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700934 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800935 if err == nil {
936 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700937 // GemPort 4069 is reserved for multicast and shared across ONUs
938 if msgObj.EntityInstance != 4069 {
939 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
940 onuLogger.WithFields(log.Fields{
941 "IntfId": o.PonPortID,
942 "OnuId": o.ID,
943 "GemPortId": msgObj.EntityInstance,
944 "SerialNumber": o.Sn(),
945 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
946 } else {
947 onuLogger.WithFields(log.Fields{
948 "IntfId": o.PonPortID,
949 "OnuId": o.ID,
950 "GemPortId": msgObj.EntityInstance,
951 "SerialNumber": o.Sn(),
952 }).Trace("storing-gem-port-id-via-omci")
953 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
954 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800955 }
956 }
957 }
958
959 // if the gemPort is valid then increment the MDS and return a successful response
960 // otherwise fail the request
961 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
962 // validation this check will need to be rewritten
963 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700964 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800965 o.MibDataSync++
966 }
967 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700968 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800969 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800970 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700971 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800972 if err == nil {
973 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
974 onuLogger.WithFields(log.Fields{
975 "IntfId": o.PonPortID,
976 "OnuId": o.ID,
977 "GemPortId": msgObj.EntityInstance,
978 "SerialNumber": o.Sn(),
979 }).Trace("freeing-gem-port-id-via-omci")
980 o.PonPort.removeGemPort(msgObj.EntityInstance)
981 }
982 }
983
Matteo Scandolob5913142021-03-19 16:10:18 -0700984 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800985 o.MibDataSync++
986 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800987 case omci.RebootRequestType:
988
Matteo Scandolob5913142021-03-19 16:10:18 -0700989 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800990
991 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800992 // we run this in a separate goroutine so that
993 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800994 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800995 if err := o.Reboot(10 * time.Second); err != nil {
996 log.WithFields(log.Fields{
997 "IntfId": o.PonPortID,
998 "OnuId": o.ID,
999 "SerialNumber": o.Sn(),
1000 "err": err,
1001 }).Error("cannot-reboot-onu-after-omci-reboot-request")
1002 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001003 }()
1004 case omci.TestRequestType:
Girish Gowdra161d27a2021-05-05 12:01:44 -07001005 var classID me.ClassID
1006 var omciResult me.Results
1007 var instID uint16
1008 responsePkt, errResp, classID, instID, omciResult = omcilib.CreateTestResponse(msg.OmciPkt, msg.OmciMsg)
1009 // Send TestResult only in case the TestResponse omci result code is me.Success
1010 if responsePkt != nil && errResp == nil && omciResult == me.Success {
1011 if testResultPkt, err := omcilib.CreateTestResult(classID, instID, msg.OmciMsg.TransactionID); err == nil {
1012 // send test results asynchronously
1013 go func() {
1014 // Send test results after a second to emulate async behavior
1015 time.Sleep(1 * time.Second)
1016 if testResultPkt != nil {
1017 if err := o.sendOmciIndication(testResultPkt, msg.OmciMsg.TransactionID, stream); err != nil {
1018 onuLogger.WithFields(log.Fields{
1019 "IntfId": o.PonPortID,
1020 "SerialNumber": o.Sn(),
1021 "omciPacket": testResultPkt,
1022 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1023 "transCorrId": msg.OmciMsg.TransactionID,
1024 }).Errorf("failed-to-send-omci-message: %v", err)
1025 }
1026 }
1027 }()
Matteo Scandolof9d43412021-01-12 11:11:34 -08001028 }
1029 }
Girish Gowdraa539f522021-02-15 23:00:45 -08001030 case omci.SynchronizeTimeRequestType:
1031 // MDS counter increment is not required for this message type
Matteo Scandolob5913142021-03-19 16:10:18 -07001032 responsePkt, _ = omcilib.CreateSyncTimeResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -08001033 case omci.StartSoftwareDownloadRequestType:
1034
1035 o.ImageSoftwareReceivedSections = 0
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301036 o.ImageSectionData = []byte{}
Matteo Scandolob5913142021-03-19 16:10:18 -07001037 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
Matteo Scandolocedde462021-03-09 17:37:16 -08001038
Matteo Scandolob5913142021-03-19 16:10:18 -07001039 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001040 o.MibDataSync++
1041 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
1042 onuLogger.WithFields(log.Fields{
1043 "OnuId": o.ID,
1044 "IntfId": o.PonPortID,
1045 "OnuSn": o.Sn(),
1046 "Err": err.Error(),
1047 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
1048 }
1049 } else {
1050 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001051 "OmciMsgType": msg.OmciMsg.MessageType,
1052 "TransCorrId": msg.OmciMsg.TransactionID,
1053 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001054 "IntfId": o.PonPortID,
1055 "SerialNumber": o.Sn(),
1056 }).Error("error-while-processing-start-software-download-request")
1057 }
1058 case omci.DownloadSectionRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001059 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001060 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001061 "OmciMsgType": msg.OmciMsg.MessageType,
1062 "TransCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001063 "EntityInstance": msgObj.EntityInstance,
1064 "SectionNumber": msgObj.SectionNumber,
1065 "SectionData": msgObj.SectionData,
1066 }).Trace("received-download-section-request")
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001067 //Extracting the first 14 bytes to use as a version for this image.
1068 if o.ImageSoftwareReceivedSections == 0 {
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001069 o.InDownloadImageVersion = string(msgObj.SectionData[0:14])
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001070 }
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301071 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
Matteo Scandolocedde462021-03-09 17:37:16 -08001072 o.ImageSoftwareReceivedSections++
1073 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1074 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1075 onuLogger.WithFields(log.Fields{
1076 "OnuId": o.ID,
1077 "IntfId": o.PonPortID,
1078 "OnuSn": o.Sn(),
1079 "Err": err.Error(),
1080 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1081 }
1082 }
1083 }
1084 case omci.DownloadSectionRequestWithResponseType:
1085 // NOTE we only need to respond if an ACK is requested
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301086 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001087 onuLogger.WithFields(log.Fields{
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301088 "OmciMsgType": msg.OmciMsg.MessageType,
1089 "TransCorrId": msg.OmciMsg.TransactionID,
1090 "EntityInstance": msgObj.EntityInstance,
1091 "SectionNumber": msgObj.SectionNumber,
1092 "SectionData": msgObj.SectionData,
1093 }).Trace("received-download-section-request-with-response-type")
1094 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
1095 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1096
1097 if errResp != nil {
1098 onuLogger.WithFields(log.Fields{
1099 "OmciMsgType": msg.OmciMsg.MessageType,
1100 "TransCorrId": msg.OmciMsg.TransactionID,
1101 "Err": errResp.Error(),
1102 "IntfId": o.PonPortID,
1103 "SerialNumber": o.Sn(),
1104 }).Error("error-while-processing-create-download-section-response")
1105 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
1106 }
1107 o.ImageSoftwareReceivedSections++
Matteo Scandolocedde462021-03-09 17:37:16 -08001108 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001109 case omci.EndSoftwareDownloadRequestType:
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001110 success := o.handleEndSoftwareDownloadRequest(msg)
Matteo Scandolocedde462021-03-09 17:37:16 -08001111
Matteo Scandolocedde462021-03-09 17:37:16 -08001112 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001113 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001114 o.MibDataSync++
1115 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1116 onuLogger.WithFields(log.Fields{
1117 "OnuId": o.ID,
1118 "IntfId": o.PonPortID,
1119 "OnuSn": o.Sn(),
1120 "Err": err.Error(),
1121 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1122 }
1123 } else {
1124 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001125 "OmciMsgType": msg.OmciMsg.MessageType,
1126 "TransCorrId": msg.OmciMsg.TransactionID,
1127 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001128 "IntfId": o.PonPortID,
1129 "SerialNumber": o.Sn(),
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001130 }).Error("error-while-responding-to-end-software-download-request")
Matteo Scandolocedde462021-03-09 17:37:16 -08001131 }
1132 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001133 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001134 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1135 onuLogger.WithFields(log.Fields{
1136 "OnuId": o.ID,
1137 "IntfId": o.PonPortID,
1138 "OnuSn": o.Sn(),
1139 "Err": err.Error(),
1140 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1141 }
1142 }
1143 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001144 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001145 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001146 o.MibDataSync++
1147 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1148 onuLogger.WithFields(log.Fields{
1149 "OnuId": o.ID,
1150 "IntfId": o.PonPortID,
1151 "OnuSn": o.Sn(),
1152 "Err": err.Error(),
1153 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1154 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001155 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001156 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001157 previousActiveImage := o.ActiveImageVersion
1158 o.ActiveImageVersion = o.StandbyImageVersion
1159 o.StandbyImageVersion = previousActiveImage
Matteo Scandolocedde462021-03-09 17:37:16 -08001160 } else {
1161 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1162 }
1163 onuLogger.WithFields(log.Fields{
1164 "OnuId": o.ID,
1165 "IntfId": o.PonPortID,
1166 "OnuSn": o.Sn(),
1167 "ActiveImageEntityId": o.ActiveImageEntityId,
1168 "CommittedImageEntityId": o.CommittedImageEntityId,
1169 }).Info("onu-software-image-activated")
1170
1171 // powercycle the ONU
1172 // we run this in a separate goroutine so that
1173 // the ActivateSoftwareResponse is sent to VOLTHA
1174 // NOTE do we need to wait before rebooting?
1175 go func() {
1176 if err := o.Reboot(10 * time.Second); err != nil {
1177 log.WithFields(log.Fields{
1178 "IntfId": o.PonPortID,
1179 "OnuId": o.ID,
1180 "SerialNumber": o.Sn(),
1181 "err": err,
1182 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1183 }
1184 }()
1185 }
1186 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001187 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001188 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001189 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001190 // TODO validate that the image to commit is:
1191 // - active
1192 // - not already committed
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001193 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandolocedde462021-03-09 17:37:16 -08001194 o.CommittedImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001195 //committed becomes standby
1196 o.StandbyImageVersion = o.CommittedImageVersion
1197 o.CommittedImageVersion = o.ActiveImageVersion
Matteo Scandolocedde462021-03-09 17:37:16 -08001198 } else {
1199 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1200 }
1201 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1202 onuLogger.WithFields(log.Fields{
1203 "OnuId": o.ID,
1204 "IntfId": o.PonPortID,
1205 "OnuSn": o.Sn(),
1206 "Err": err.Error(),
1207 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1208 }
1209 onuLogger.WithFields(log.Fields{
1210 "OnuId": o.ID,
1211 "IntfId": o.PonPortID,
1212 "OnuSn": o.Sn(),
1213 "ActiveImageEntityId": o.ActiveImageEntityId,
1214 "CommittedImageEntityId": o.CommittedImageEntityId,
1215 }).Info("onu-software-image-committed")
1216 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301217 case omci.GetAllAlarmsRequestType:
1218 // Reset the alarm sequence number on receiving get all alarms request.
1219 o.onuAlarmsInfoLock.Lock()
1220 for key, alarmInfo := range o.onuAlarmsInfo {
1221 // reset the alarm sequence no
1222 alarmInfo.SequenceNo = 0
1223 o.onuAlarmsInfo[key] = alarmInfo
1224 }
1225 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001226 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301227 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001228 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301229 responsePkt = nil //Do not send any response for error case
1230 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001231 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001232 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001233 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1234 "omciPkt": msg.OmciPkt,
1235 "omciMsgType": msg.OmciMsg.MessageType,
1236 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001237 "IntfId": o.PonPortID,
1238 "SerialNumber": o.Sn(),
1239 }).Warnf("OMCI-message-not-supported")
1240 }
1241
1242 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001243 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001244 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001245 "IntfId": o.PonPortID,
1246 "SerialNumber": o.Sn(),
1247 "omciPacket": responsePkt,
1248 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1249 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001250 }).Errorf("failed-to-send-omci-message: %v", err)
1251 }
1252 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001253
Pragya Arya324337e2020-02-20 14:35:08 +05301254 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001255 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001256}
Pragya Arya324337e2020-02-20 14:35:08 +05301257
Matteo Scandolof9d43412021-01-12 11:11:34 -08001258// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1259func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1260 indication := &openolt.Indication_OmciInd{
1261 OmciInd: &openolt.OmciIndication{
1262 IntfId: o.PonPortID,
1263 OnuId: o.ID,
1264 Pkt: responsePkt,
1265 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001266 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001267 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1268 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001269 }
1270 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001271 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001272 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001273 "omciPacket": indication.OmciInd.Pkt,
1274 "transCorrId": txId,
1275 }).Trace("omci-message-sent")
1276 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001277}
1278
Matteo Scandolo8a574812021-05-20 15:18:53 -07001279// FindUniById retrieves a UNI by ID
1280func (o *Onu) FindUniById(uniID uint32) (*UniPort, error) {
1281 for _, u := range o.UniPorts {
1282 uni := u.(*UniPort)
1283 if uni.ID == uniID {
1284 return uni, nil
1285 }
Matteo Scandolo27428702019-10-11 16:21:16 -07001286 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001287 return nil, fmt.Errorf("cannot-find-uni-with-id-%d-on-onu-%s", uniID, o.Sn())
1288}
1289
Elia Battistonac63b112022-01-12 18:40:49 +01001290// FindPotsById retrieves a POTS port by ID
1291func (o *Onu) FindPotsById(uniID uint32) (*PotsPort, error) {
1292 for _, p := range o.PotsPorts {
1293 pots := p.(*PotsPort)
1294 if pots.ID == uniID {
1295 return pots, nil
1296 }
1297 }
1298 return nil, fmt.Errorf("cannot-find-pots-with-id-%d-on-onu-%s", uniID, o.Sn())
1299}
1300
Matteo Scandolo8a574812021-05-20 15:18:53 -07001301// FindUniByEntityId retrieves a uni by MeID (the OMCI entity ID)
1302func (o *Onu) FindUniByEntityId(meId uint16) (*UniPort, error) {
1303 entityId := omcilib.EntityID{}.FromUint16(meId)
1304 for _, u := range o.UniPorts {
1305 uni := u.(*UniPort)
1306 if uni.MeId.Equals(entityId) {
1307 return uni, nil
1308 }
1309 }
1310 return nil, fmt.Errorf("cannot-find-uni-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
Matteo Scandolo27428702019-10-11 16:21:16 -07001311}
1312
Elia Battistonac63b112022-01-12 18:40:49 +01001313// FindPotsByEntityId retrieves a POTS uni by MeID (the OMCI entity ID)
1314func (o *Onu) FindPotsByEntityId(meId uint16) (*PotsPort, error) {
1315 entityId := omcilib.EntityID{}.FromUint16(meId)
1316 for _, p := range o.PotsPorts {
1317 pots := p.(*PotsPort)
1318 if pots.MeId.Equals(entityId) {
1319 return pots, nil
1320 }
1321 }
1322 return nil, fmt.Errorf("cannot-find-pots-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
1323}
1324
William Kurkian0418bc82019-11-06 12:16:24 -05001325func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001326 onuLogger.WithFields(log.Fields{
1327 "IntfId": o.PonPortID,
1328 "OnuId": id,
1329 "SerialNumber": o.Sn(),
1330 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001331 o.ID = id
1332}
1333
Matteo Scandolof9d43412021-01-12 11:11:34 -08001334func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001335 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001336 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001337 "Cookie": msg.Flow.Cookie,
1338 "DstPort": msg.Flow.Classifier.DstPort,
1339 "FlowId": msg.Flow.FlowId,
1340 "FlowType": msg.Flow.FlowType,
1341 "GemportId": msg.Flow.GemportId,
1342 "InnerVlan": msg.Flow.Classifier.IVid,
1343 "IntfId": msg.Flow.AccessIntfId,
1344 "IpProto": msg.Flow.Classifier.IpProto,
1345 "OnuId": msg.Flow.OnuId,
1346 "OnuSn": o.Sn(),
1347 "OuterVlan": msg.Flow.Classifier.OVid,
1348 "PortNo": msg.Flow.PortNo,
1349 "SrcPort": msg.Flow.Classifier.SrcPort,
1350 "UniID": msg.Flow.UniId,
1351 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1352 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1353 "ClassifierIVid": msg.Flow.Classifier.IVid,
1354 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001355 "ReplicateFlow": msg.Flow.ReplicateFlow,
1356 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001357 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001358
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001359 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001360
1361 var gemPortId uint32
1362 if msg.Flow.ReplicateFlow {
1363 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1364 // first available gemport (we only need to send one packet)
1365 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1366 gemPortId = msg.Flow.PbitToGemport[0]
1367 } else {
1368 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1369 gemPortId = uint32(msg.Flow.GemportId)
1370 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001371
1372 uni, err := o.FindUniById(uint32(msg.Flow.UniId))
1373 if err != nil {
1374 onuLogger.WithFields(log.Fields{
1375 "IntfId": o.PonPortID,
1376 "OnuId": o.ID,
1377 "UniId": msg.Flow.UniId,
1378 "PortNo": msg.Flow.PortNo,
1379 "SerialNumber": o.Sn(),
1380 "FlowId": msg.Flow.FlowId,
1381 "FlowType": msg.Flow.FlowType,
1382 }).Error("cannot-find-uni-port-for-flow")
1383 }
1384
1385 uni.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
1386 uni.StorePortNo(msg.Flow.PortNo)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001387
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001388 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001389 uni.HandleAuth()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001390 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1391 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001392 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001393 uni.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001394 }
1395}
1396
Matteo Scandolof9d43412021-01-12 11:11:34 -08001397func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001398 onuLogger.WithFields(log.Fields{
1399 "IntfId": o.PonPortID,
1400 "OnuId": o.ID,
1401 "SerialNumber": o.Sn(),
1402 "FlowId": msg.Flow.FlowId,
1403 "FlowType": msg.Flow.FlowType,
1404 }).Debug("ONU receives FlowRemove")
1405
1406 for idx, flow := range o.FlowIds {
1407 // If the gemport is found, delete it from local cache.
1408 if flow == msg.Flow.FlowId {
1409 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1410 break
1411 }
1412 }
1413
1414 if len(o.FlowIds) == 0 {
1415 onuLogger.WithFields(log.Fields{
1416 "IntfId": o.PonPortID,
1417 "OnuId": o.ID,
1418 "SerialNumber": o.Sn(),
1419 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001420
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301421 // check if ONU delete is performed and
1422 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001423 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301424 close(o.Channel)
1425 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001426 }
1427}
1428
Matteo Scandolocedde462021-03-09 17:37:16 -08001429func (o *Onu) Reboot(timeout time.Duration) error {
1430 onuLogger.WithFields(log.Fields{
1431 "IntfId": o.PonPortID,
1432 "OnuId": o.ID,
1433 "SerialNumber": o.Sn(),
1434 }).Debug("shutting-down-onu")
1435 if err := o.HandleShutdownONU(); err != nil {
1436 return err
1437 }
1438 time.Sleep(timeout)
1439 onuLogger.WithFields(log.Fields{
1440 "IntfId": o.PonPortID,
1441 "OnuId": o.ID,
1442 "SerialNumber": o.Sn(),
1443 }).Debug("power-on-onu")
1444 if err := o.HandlePowerOnONU(); err != nil {
1445 return err
1446 }
1447 return nil
1448}
1449
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001450// returns true if the request is successful, false otherwise
1451func (o *Onu) handleEndSoftwareDownloadRequest(msg bbsim.OmciMessage) bool {
1452 msgObj, err := omcilib.ParseEndSoftwareDownloadRequest(msg.OmciPkt)
1453 if err != nil {
1454 onuLogger.WithFields(log.Fields{
1455 "OmciMsgType": msg.OmciMsg.MessageType,
1456 "TransCorrId": msg.OmciMsg.TransactionID,
1457 "Err": err.Error(),
1458 "IntfId": o.PonPortID,
1459 "SerialNumber": o.Sn(),
1460 }).Error("error-while-processing-end-software-download-request")
1461 return false
1462 }
1463
1464 onuLogger.WithFields(log.Fields{
1465 "OnuId": o.ID,
1466 "IntfId": o.PonPortID,
1467 "OnuSn": o.Sn(),
1468 "msgObj": msgObj,
1469 }).Trace("EndSoftwareDownloadRequest received message")
1470
1471 // if the image download is ongoing and we receive a message with
1472 // ImageSize = 0 and Crc = 4294967295 (0xFFFFFFFF) respond with success
1473 if o.ImageSoftwareReceivedSections > 0 &&
1474 msgObj.ImageSize == 0 &&
1475 msgObj.CRC32 == 4294967295 {
1476 o.ImageSoftwareReceivedSections = 0
1477 // NOTE potentially we may want to add a ONU state to reflect
1478 // the software download abort
1479 return true
1480 }
1481
1482 // In the startSoftwareDownload we get the image size and the window size.
1483 // We calculate how many DownloadSection we should receive and validate
1484 // that we got the correct amount when we receive this message
1485 // If the received sections are different from the expected sections
1486 // respond with failure
1487 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1488 onuLogger.WithFields(log.Fields{
1489 "OnuId": o.ID,
1490 "IntfId": o.PonPortID,
1491 "OnuSn": o.Sn(),
1492 "ExpectedSections": o.ImageSoftwareExpectedSections,
1493 "ReceivedSections": o.ImageSoftwareReceivedSections,
1494 }).Errorf("onu-did-not-receive-all-image-sections")
1495 return false
1496 }
1497
1498 // check the received CRC vs the computed CRC
1499 computedCRC := crc32a.Checksum(o.ImageSectionData[:int(msgObj.ImageSize)])
1500 //Convert the crc to network byte order
1501 var byteSlice = make([]byte, 4)
1502 binary.LittleEndian.PutUint32(byteSlice, computedCRC)
1503 computedCRC = binary.BigEndian.Uint32(byteSlice)
1504 if msgObj.CRC32 != computedCRC {
1505 onuLogger.WithFields(log.Fields{
1506 "OnuId": o.ID,
1507 "IntfId": o.PonPortID,
1508 "OnuSn": o.Sn(),
1509 "ReceivedCRC": msgObj.CRC32,
1510 "CalculatedCRC": computedCRC,
1511 }).Errorf("onu-image-crc-validation-failed")
1512 return false
1513 }
1514
1515 o.StandbyImageVersion = o.InDownloadImageVersion
1516 onuLogger.WithFields(log.Fields{
1517 "OnuId": o.ID,
1518 "IntfId": o.PonPortID,
1519 "OnuSn": o.Sn(),
1520 "StandbyVersion": o.StandbyImageVersion,
1521 }).Debug("onu-image-version-updated")
1522 return true
1523}
1524
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001525// BBR methods
1526
1527func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1528 omciMsg := openolt.OmciMsg{
1529 IntfId: intfId,
1530 OnuId: onuId,
1531 Pkt: pktBytes,
1532 }
1533
1534 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1535 log.WithFields(log.Fields{
1536 "IntfId": intfId,
1537 "OnuId": onuId,
1538 "SerialNumber": common.OnuSnToString(sn),
1539 "Pkt": omciMsg.Pkt,
1540 }).Fatalf("Failed to send MIB Reset")
1541 }
1542 log.WithFields(log.Fields{
1543 "IntfId": intfId,
1544 "OnuId": onuId,
1545 "SerialNumber": common.OnuSnToString(sn),
1546 "Pkt": omciMsg.Pkt,
1547 }).Tracef("Sent OMCI message %s", msgType)
1548}
1549
1550func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1551 var next uint16
1552 if len(highPriority) > 0 && highPriority[0] {
1553 next = onu.hpTid
1554 onu.hpTid += 1
1555 if onu.hpTid < 0x8000 {
1556 onu.hpTid = 0x8000
1557 }
1558 } else {
1559 next = onu.tid
1560 onu.tid += 1
1561 if onu.tid >= 0x8000 {
1562 onu.tid = 1
1563 }
1564 }
1565 return next
1566}
1567
1568// TODO move this method in responders/omcisim
Matteo Scandolo8a574812021-05-20 15:18:53 -07001569// StartOmci is called in BBR to start the OMCI state machine
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001570func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1571 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1572 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1573}
1574
Matteo Scandolof9d43412021-01-12 11:11:34 -08001575// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1576func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1577
1578 // we need to encode the packet in HEX
1579 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1580 hex.Encode(pkt, msg.OmciInd.Pkt)
1581 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1582 if err != nil {
1583 log.WithFields(log.Fields{
1584 "IntfId": o.PonPortID,
1585 "SerialNumber": o.Sn(),
1586 "omciPacket": msg.OmciInd.Pkt,
1587 }).Error("BBR Cannot parse OMCI packet")
1588 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001589
1590 log.WithFields(log.Fields{
1591 "IntfId": msg.OmciInd.IntfId,
1592 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001593 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001594 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001595 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301596 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001597 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001598 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001599 log.WithFields(log.Fields{
1600 "IntfId": msg.OmciInd.IntfId,
1601 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001602 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001603 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001604 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001605 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001606 case omci.MibResetResponseType:
1607 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1608 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1609 case omci.MibUploadResponseType:
1610 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1611 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1612 case omci.MibUploadNextResponseType:
1613 o.seqNumber++
Matteo Scandolo8a574812021-05-20 15:18:53 -07001614 // once the mibUpload is complete send a SetRequest for the PPTP to enable the UNI
1615 // NOTE that in BBR we only enable the first UNI
1616 if o.seqNumber == o.MibDb.NumberOfCommands {
1617 meId := omcilib.GenerateUniPortEntityId(1)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001618
Matteo Scandolo8a574812021-05-20 15:18:53 -07001619 meParams := me.ParamData{
1620 EntityID: meId.ToUint16(),
1621 Attributes: me.AttributeValueMap{"AdministrativeState": 0},
1622 }
1623 managedEntity, omciError := me.NewPhysicalPathTerminationPointEthernetUni(meParams)
1624 if omciError.GetError() != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001625 onuLogger.WithFields(log.Fields{
1626 "OnuId": o.ID,
1627 "IntfId": o.PonPortID,
1628 "OnuSn": o.Sn(),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001629 }).Fatal(omciError.GetError())
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001630 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001631
1632 setPPtp, _ := omcilib.CreateSetRequest(managedEntity, 1)
1633 sendOmciMsg(setPPtp, o.PonPortID, o.ID, o.SerialNumber, "setRquest", client)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001634 } else {
1635 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1636 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001637 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001638 case omci.SetResponseType:
1639 // once we set the PPTP to active we can start sending flows
1640
1641 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
1642 onuLogger.WithFields(log.Fields{
1643 "OnuId": o.ID,
1644 "IntfId": o.PonPortID,
1645 "OnuSn": o.Sn(),
1646 }).Errorf("Error while transitioning ONU State %v", err)
1647 }
1648 case omci.AlarmNotificationType:
1649 log.Info("bbr-received-alarm")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001650 }
1651}
1652
1653func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1654
1655 classifierProto := openolt.Classifier{
1656 EthType: uint32(layers.EthernetTypeEAPOL),
1657 OVid: 4091,
1658 }
1659
1660 actionProto := openolt.Action{}
1661
1662 downstreamFlow := openolt.Flow{
1663 AccessIntfId: int32(o.PonPortID),
1664 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001665 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001666 FlowId: uint64(o.ID),
Elia Battiston560e9552022-01-31 10:44:15 +01001667 FlowType: flowTypeDownstream,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001668 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001669 Classifier: &classifierProto,
1670 Action: &actionProto,
1671 Priority: int32(100),
1672 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001673 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1674 // AllocId and GemPorts need to be unique per PON
1675 // for now use the ONU-ID, will need to change once we support multiple UNIs
1676 AllocId: int32(o.ID),
1677 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001678 }
1679
1680 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1681 log.WithFields(log.Fields{
1682 "IntfId": o.PonPortID,
1683 "OnuId": o.ID,
1684 "FlowId": downstreamFlow.FlowId,
1685 "PortNo": downstreamFlow.PortNo,
1686 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001687 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001688 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001689 }
1690 log.WithFields(log.Fields{
1691 "IntfId": o.PonPortID,
1692 "OnuId": o.ID,
1693 "FlowId": downstreamFlow.FlowId,
1694 "PortNo": downstreamFlow.PortNo,
1695 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1696 }).Info("Sent EAPOL Flow")
1697}
1698
1699func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001700
Matteo Scandolo8a574812021-05-20 15:18:53 -07001701 // BBR only works with a single UNI and a single service (ATT HSIA)
1702 hsia := o.UniPorts[0].(*UniPort).Services[0].(*Service)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001703 classifierProto := openolt.Classifier{
1704 EthType: uint32(layers.EthernetTypeIPv4),
1705 SrcPort: uint32(68),
1706 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001707 OVid: uint32(hsia.CTag),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001708 OPbits: 255,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001709 }
1710
1711 actionProto := openolt.Action{}
1712
1713 downstreamFlow := openolt.Flow{
1714 AccessIntfId: int32(o.PonPortID),
1715 OnuId: int32(o.ID),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001716 UniId: int32(0), // BBR only supports a single UNI
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001717 FlowId: uint64(o.ID),
Elia Battiston560e9552022-01-31 10:44:15 +01001718 FlowType: flowTypeDownstream,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001719 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001720 Classifier: &classifierProto,
1721 Action: &actionProto,
1722 Priority: int32(100),
1723 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001724 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1725 // AllocId and GemPorts need to be unique per PON
1726 // for now use the ONU-ID, will need to change once we support multiple UNIs
1727 AllocId: int32(o.ID),
1728 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001729 }
1730
1731 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1732 log.WithFields(log.Fields{
1733 "IntfId": o.PonPortID,
1734 "OnuId": o.ID,
1735 "FlowId": downstreamFlow.FlowId,
1736 "PortNo": downstreamFlow.PortNo,
1737 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001738 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001739 }).Fatalf("Failed to send DHCP Flow")
1740 }
1741 log.WithFields(log.Fields{
1742 "IntfId": o.PonPortID,
1743 "OnuId": o.ID,
1744 "FlowId": downstreamFlow.FlowId,
1745 "PortNo": downstreamFlow.PortNo,
1746 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1747 }).Info("Sent DHCP Flow")
1748}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301749
Andrea Campanellacc9b1662022-01-26 17:47:48 +01001750// DeleteFlow method search and delete flowKey from the onu flows slice
1751func (onu *Onu) DeleteFlow(key FlowKey) {
1752 for pos, flowKey := range onu.Flows {
1753 if flowKey == key {
1754 // delete the flowKey by shifting all flowKeys by one
1755 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1756 t := make([]FlowKey, len(onu.Flows))
1757 copy(t, onu.Flows)
1758 onu.Flows = t
Pragya Arya8bdb4532020-03-02 17:08:09 +05301759 break
1760 }
1761 }
1762}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301763
1764func (onu *Onu) ReDiscoverOnu() {
1765 // Wait for few seconds to be sure of the cleanup
1766 time.Sleep(5 * time.Second)
1767
1768 onuLogger.WithFields(log.Fields{
1769 "IntfId": onu.PonPortID,
1770 "OnuId": onu.ID,
1771 "OnuSn": onu.Sn(),
1772 }).Debug("Send ONU Re-Discovery")
1773
1774 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001775 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301776 log.WithFields(log.Fields{
1777 "IntfId": onu.PonPortID,
1778 "OnuSn": onu.Sn(),
1779 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001780 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301781 }
1782
Matteo Scandolocedde462021-03-09 17:37:16 -08001783 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301784 log.WithFields(log.Fields{
1785 "IntfId": onu.PonPortID,
1786 "OnuSn": onu.Sn(),
1787 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001788 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301789 }
1790}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001791
Matteo Scandolo8a574812021-05-20 15:18:53 -07001792// deprecated, delegate this to the uniPort
Matteo Scandolo4a036262020-08-17 15:56:13 -07001793func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001794 // FIXME is there a better way to avoid this loop?
1795 for _, u := range onu.UniPorts {
1796 uni := u.(*UniPort)
1797 for _, s := range uni.Services {
1798 service := s.(*Service)
1799 if service.HwAddress.String() == macAddress.String() {
1800 return service, nil
1801 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001802 }
1803 }
1804 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1805}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301806
Matteo Scandolo8a574812021-05-20 15:18:53 -07001807func (onu *Onu) findUniByPortNo(portNo uint32) (*UniPort, error) {
1808 for _, u := range onu.UniPorts {
1809 uni := u.(*UniPort)
1810 if uni.PortNo == portNo {
1811 return uni, nil
1812 }
1813 }
1814 return nil, fmt.Errorf("cannot-find-uni-with-port-no-%d", portNo)
1815}
1816
Himani Chawla13b1ee02021-03-15 01:43:53 +05301817func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1818 switch alarmType {
1819 case "ONU_ALARM_LOS":
1820 msg := bbsim.Message{
1821 Type: bbsim.UniStatusAlarm,
1822 Data: bbsim.UniStatusAlarmMessage{
1823 OnuSN: o.SerialNumber,
1824 OnuID: o.ID,
1825 EntityID: 257,
1826 RaiseOMCIAlarm: raiseOMCIAlarm,
1827 },
1828 }
1829 o.Channel <- msg
1830 }
1831
1832}
1833
1834func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1835 o.onuAlarmsInfoLock.Lock()
1836 defer o.onuAlarmsInfoLock.Unlock()
1837 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1838 if alarmInfo.SequenceNo == 255 {
1839 alarmInfo.SequenceNo = 1
1840 } else {
1841 alarmInfo.SequenceNo++
1842 }
1843 o.onuAlarmsInfo[key] = alarmInfo
1844 return alarmInfo.SequenceNo
1845 } else {
1846 // This is the first time alarm notification message is being sent
1847 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1848 SequenceNo: 1,
1849 }
1850 return 1
1851 }
1852}
Elia Battistonfe017662022-01-05 11:43:16 +01001853
1854func (o *Onu) InvalidateMibDataSync() {
1855 rand.Seed(time.Now().UnixNano())
1856 r := uint8(rand.Intn(10) + 1)
1857
1858 o.MibDataSync += r
1859
1860 // Since MibDataSync is a uint8, summing to it will never
1861 // result in a value higher than 255, but could be 0
1862 if o.MibDataSync == 0 {
1863 o.MibDataSync++
1864 }
1865}