blob: 97c1adc305d5c88d5d04892d4a33420ebb0f6093 [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
Pragya Arya8bdb4532020-03-02 17:08:09 +053096type FlowKey struct {
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070097 ID uint64
Pragya Arya8bdb4532020-03-02 17:08:09 +053098 Direction string
99}
100
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700101type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800102 ID uint32
103 PonPortID uint32
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700104 PonPort *PonPort
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800105 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +0530106 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
107 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandolo4a036262020-08-17 15:56:13 -0700108
Matteo Scandolo4a036262020-08-17 15:56:13 -0700109 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800110 // ONU State
Matteo Scandolo8a574812021-05-20 15:18:53 -0700111 UniPorts []UniPortIf
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700112 Flows []FlowKey
113 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
163 Flows: []FlowKey{},
164 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
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530293 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100294 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolo8a574812021-05-20 15:18:53 -0700295 // NOTE may need to wait for the UNIs to be down too before shutting down the channel
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530296 if len(o.FlowIds) == 0 {
297 close(o.Channel)
298 }
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700299 },
300 fmt.Sprintf("enter_%s", OnuStatePonDisabled): func(event *fsm.Event) {
301 o.cleanupOnuState()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700302 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700303 // BBR states
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700304 fmt.Sprintf("enter_%s", BbrOnuStateEapolFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800305 msg := bbsim.Message{
306 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700307 }
308 o.Channel <- msg
309 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700310 fmt.Sprintf("enter_%s", BbrOnuStateDhcpFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800311 msg := bbsim.Message{
312 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700313 }
314 o.Channel <- msg
315 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700316 },
317 )
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700318 onuLogger.WithFields(log.Fields{
319 "OnuId": o.ID,
320 "IntfId": o.PonPortID,
321 "OnuSn": o.Sn(),
322 "NumUni": olt.NumUni,
323 }).Debug("creating-uni-ports")
324 for i := 0; i < olt.NumUni; i++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700325 uni, err := NewUniPort(uint32(i), &o, nextCtag, nextStag)
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700326 if err != nil {
327 onuLogger.WithFields(log.Fields{
328 "OnuId": o.ID,
329 "IntfId": o.PonPortID,
330 "OnuSn": o.Sn(),
331 "Err": err,
332 }).Fatal("cannot-create-uni-port")
333 }
334 o.UniPorts = append(o.UniPorts, uni)
335 }
336
337 mibDb, err := omcilib.GenerateMibDatabase(len(o.UniPorts))
338 if err != nil {
339 onuLogger.WithFields(log.Fields{
340 "OnuId": o.ID,
341 "IntfId": o.PonPortID,
342 "OnuSn": o.Sn(),
343 }).Fatal("cannot-generate-mibdb-for-onu")
344 }
345 o.MibDb = mibDb
346
Matteo Scandolo27428702019-10-11 16:21:16 -0700347 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700348}
349
William Kurkian0418bc82019-11-06 12:16:24 -0500350func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700351 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700352 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700353 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700354 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700355 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
356}
357
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700358// cleanupOnuState this method is to clean the local state when the ONU is disabled
359func (o *Onu) cleanupOnuState() {
360 // clean the ONU state
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700361 o.Flows = []FlowKey{}
362 o.PonPort.removeOnuId(o.ID)
363 o.PonPort.removeAllocId(o.SerialNumber)
364 o.PonPort.removeGemPortBySn(o.SerialNumber)
365
366 o.onuAlarmsInfoLock.Lock()
367 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
368 o.onuAlarmsInfoLock.Unlock()
369}
370
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100371// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000372func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700373 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100374 "onuID": o.ID,
375 "onuSN": o.Sn(),
376 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700377 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100378 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700379
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700380 defer onuLogger.WithFields(log.Fields{
381 "onuID": o.ID,
382 "onuSN": o.Sn(),
383 "stream": stream,
384 }).Debug("Stopped handling ONU Indication Channel")
385
David Bainbridge103cf022019-12-16 20:11:35 +0000386loop:
387 for {
388 select {
389 case <-ctx.Done():
390 onuLogger.WithFields(log.Fields{
391 "onuID": o.ID,
392 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700393 }).Debug("ONU message handling canceled via context")
394 break loop
395 case <-stream.Context().Done():
396 onuLogger.WithFields(log.Fields{
397 "onuID": o.ID,
398 "onuSN": o.Sn(),
399 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000400 break loop
401 case message, ok := <-o.Channel:
402 if !ok || ctx.Err() != nil {
403 onuLogger.WithFields(log.Fields{
404 "onuID": o.ID,
405 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700406 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000407 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700408 }
David Bainbridge103cf022019-12-16 20:11:35 +0000409 onuLogger.WithFields(log.Fields{
410 "onuID": o.ID,
411 "onuSN": o.Sn(),
412 "messageType": message.Type,
413 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700414
David Bainbridge103cf022019-12-16 20:11:35 +0000415 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800416 case bbsim.OnuDiscIndication:
417 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000418 // 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 +0530419 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000420 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800421 case bbsim.OnuIndication:
422 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000423 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800424 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800425 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800426 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200427 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800428 case bbsim.UniStatusAlarm:
429 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530430 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
431 MeInstance: msg.EntityID,
432 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
433 }
434 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
435 o.onuAlarmsInfoLock.Lock()
436 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
437 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
438 if pkt != nil { //pkt will be nil if we are unable to create the alarm
439 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
440 onuLogger.WithFields(log.Fields{
441 "IntfId": o.PonPortID,
442 "SerialNumber": o.Sn(),
443 "omciPacket": pkt,
444 "adminState": msg.AdminState,
445 "entityID": msg.EntityID,
446 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
447 alarmInfo.SequenceNo--
448 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800449 onuLogger.WithFields(log.Fields{
450 "IntfId": o.PonPortID,
451 "SerialNumber": o.Sn(),
452 "omciPacket": pkt,
453 "adminState": msg.AdminState,
454 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530455 }).Trace("UNI-Link-alarm-sent")
456 if alarmBitMap == [28]byte{0} {
457 delete(o.onuAlarmsInfo, onuAlarmMapKey)
458 } else {
459 alarmInfo.AlarmBitMap = alarmBitMap
460 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
461 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800462 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530463 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800464 case bbsim.FlowAdd:
465 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700466 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800467 case bbsim.FlowRemoved:
468 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700469 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800470 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700471
Matteo Scandolof9d43412021-01-12 11:11:34 -0800472 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000473
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700474 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000475 "IntfId": msg.IntfId,
476 "OnuId": msg.OnuId,
477 "pktType": msg.Type,
478 }).Trace("Received OnuPacketOut Message")
479
Matteo Scandolo8a574812021-05-20 15:18:53 -0700480 uni, err := o.findUniByPortNo(msg.PortNo)
Matteo Scandolo618a6582020-09-09 12:21:29 -0700481
Matteo Scandolo8a574812021-05-20 15:18:53 -0700482 if err != nil {
483 onuLogger.WithFields(log.Fields{
484 "IntfId": msg.IntfId,
485 "OnuId": msg.OnuId,
486 "pktType": msg.Type,
487 "portNo": msg.PortNo,
488 "MacAddress": msg.MacAddress,
489 "Pkt": hex.EncodeToString(msg.Packet.Data()),
490 "OnuSn": o.Sn(),
491 }).Error("Cannot find Uni associated with packet")
492 return
David Bainbridge103cf022019-12-16 20:11:35 +0000493 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700494 uni.PacketCh <- msg
495 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800496 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000497 // NOTE we only receive BBR packets here.
498 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
499 // 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 -0800500 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000501
Matteo Scandolo8a574812021-05-20 15:18:53 -0700502 onuLogger.WithFields(log.Fields{
503 "IntfId": msg.IntfId,
504 "OnuId": msg.OnuId,
505 "PortNo": msg.PortNo,
506 "GemPortId": msg.GemPortId,
507 "pktType": msg.Type,
David Bainbridge103cf022019-12-16 20:11:35 +0000508 }).Trace("Received OnuPacketIn Message")
509
Matteo Scandolo8a574812021-05-20 15:18:53 -0700510 uni, err := o.findUniByPortNo(msg.PortNo)
511 if err != nil {
512 onuLogger.WithFields(log.Fields{
513 "IntfId": msg.IntfId,
514 "OnuId": msg.OnuId,
515 "PortNo": msg.PortNo,
516 "GemPortId": msg.GemPortId,
517 "pktType": msg.Type,
518 }).Error(err.Error())
519 }
520
521 // BBR has one service and one UNI
522 serviceId := uint32(0)
523 oltId := 0
David Bainbridge103cf022019-12-16 20:11:35 +0000524 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700525 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 +0000526 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700527 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000528 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800529 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800530 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800531 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
532 o.handleOmciResponse(msg, client)
533 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000534 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800535 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000536 o.sendDhcpFlow(client)
537 default:
538 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700539 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700540 }
541 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700542}
543
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800544func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700545 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700546 sn.VendorId = []byte("BBSM")
547 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700548 return sn
549}
550
Matteo Scandolof9d43412021-01-12 11:11:34 -0800551func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700552 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800553 IntfId: o.PonPortID,
554 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700555 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700556
Matteo Scandolo4747d292019-08-05 11:50:18 -0700557 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700558 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700559 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700560 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700561
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700562 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800563 "IntfId": o.PonPortID,
564 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700565 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700566 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800567 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800568
569 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
570 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800571 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800572 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800573 o.sendOnuDiscIndication(msg, stream)
574 }
575 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700576}
577
Matteo Scandolof9d43412021-01-12 11:11:34 -0800578func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800579 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
580 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700581
582 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700583 IntfId: o.PonPortID,
584 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700585 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700586 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700587 SerialNumber: o.SerialNumber,
588 }}
589 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800590 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700591 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700592 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700593 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700594 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800595 "IntfId": o.PonPortID,
596 "OnuId": o.ID,
597 "VolthaOnuId": msg.OnuID,
598 "OperState": msg.OperState.String(),
599 "AdminState": msg.OperState.String(),
600 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700601 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700602
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700603}
604
Matteo Scandolof9d43412021-01-12 11:11:34 -0800605func (o *Onu) HandleShutdownONU() error {
606
607 dyingGasp := pb.ONUAlarmRequest{
608 AlarmType: "DYING_GASP",
609 SerialNumber: o.Sn(),
610 Status: "on",
611 }
612
613 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
614 onuLogger.WithFields(log.Fields{
615 "OnuId": o.ID,
616 "IntfId": o.PonPortID,
617 "OnuSn": o.Sn(),
618 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
619 return err
620 }
621
622 losReq := pb.ONUAlarmRequest{
623 AlarmType: "ONU_ALARM_LOS",
624 SerialNumber: o.Sn(),
625 Status: "on",
626 }
627
628 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
629 onuLogger.WithFields(log.Fields{
630 "OnuId": o.ID,
631 "IntfId": o.PonPortID,
632 "OnuSn": o.Sn(),
633 }).Errorf("Cannot send LOS: %s", err.Error())
634
635 return err
636 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530637 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800638 // TODO if it's the last ONU on the PON, then send a PON LOS
639
Matteo Scandolocedde462021-03-09 17:37:16 -0800640 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800641 onuLogger.WithFields(log.Fields{
642 "OnuId": o.ID,
643 "IntfId": o.PonPortID,
644 "OnuSn": o.Sn(),
645 }).Errorf("Cannot shutdown ONU: %s", err.Error())
646 return err
647 }
648
649 return nil
650}
651
652func (o *Onu) HandlePowerOnONU() error {
653 intitalState := o.InternalState.Current()
654
655 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800656 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
657 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800658 onuLogger.WithFields(log.Fields{
659 "OnuId": o.ID,
660 "IntfId": o.PonPortID,
661 "OnuSn": o.Sn(),
662 }).Errorf("Cannot poweron ONU: %s", err.Error())
663 return err
664 }
665 }
666
667 // turn off the LOS Alarm
668 losReq := pb.ONUAlarmRequest{
669 AlarmType: "ONU_ALARM_LOS",
670 SerialNumber: o.Sn(),
671 Status: "off",
672 }
673
674 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
675 onuLogger.WithFields(log.Fields{
676 "OnuId": o.ID,
677 "IntfId": o.PonPortID,
678 "OnuSn": o.Sn(),
679 }).Errorf("Cannot send LOS: %s", err.Error())
680 return err
681 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530682 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800683
684 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800685 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800686 onuLogger.WithFields(log.Fields{
687 "OnuId": o.ID,
688 "IntfId": o.PonPortID,
689 "OnuSn": o.Sn(),
690 }).Errorf("Cannot poweron ONU: %s", err.Error())
691 return err
692 }
693
694 // move o directly to enable state only when its a powercycle case
695 // in case of first time o poweron o will be moved to enable on
696 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800697 if intitalState == OnuStateDisabled {
698 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800699 onuLogger.WithFields(log.Fields{
700 "OnuId": o.ID,
701 "IntfId": o.PonPortID,
702 "OnuSn": o.Sn(),
703 }).Errorf("Cannot enable ONU: %s", err.Error())
704 return err
705 }
706 }
707
708 return nil
709}
710
711func (o *Onu) SetAlarm(alarmType string, status string) error {
712 alarmReq := pb.ONUAlarmRequest{
713 AlarmType: alarmType,
714 SerialNumber: o.Sn(),
715 Status: status,
716 }
717
718 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
719 if err != nil {
720 return err
721 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530722 raiseAlarm := false
723 if alarmReq.Status == "on" {
724 raiseAlarm = true
725 }
726 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800727 return nil
728}
729
730func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530731 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700732 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530733 if err != nil {
734 log.Errorf("error in getting msgType %v", err)
735 return
736 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800737 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530738 o.seqNumber = 0
739 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800740 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530741 o.seqNumber++
742 if o.seqNumber > 290 {
743 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
744 }
745 }
746 }
747}
748
Matteo Scandolof9d43412021-01-12 11:11:34 -0800749// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
750// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200751func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800752
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700753 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700754 "omciMsgType": msg.OmciMsg.MessageType,
755 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
756 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700757 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700758 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800759 }).Trace("omci-message-decoded")
760
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000761 if o.OmciMsgCounter < maxOmciMsgCounter {
762 o.OmciMsgCounter++
763 } else {
764 o.OmciMsgCounter = 1
765 }
766 if o.OmciMsgCounter > o.OmciResponseRate {
767 onuLogger.WithFields(log.Fields{
768 "OmciMsgCounter": o.OmciMsgCounter,
769 "OmciResponseRate": o.OmciResponseRate,
770 "omciMsgType": msg.OmciMsg.MessageType,
Matteo Scandoloa96e2242021-09-28 10:13:17 -0700771 "txId": msg.OmciMsg.TransactionID,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200772 }).Debug("skipping-omci-msg-response")
773 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000774 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800775 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800776 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700777 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800778 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800779 onuLogger.WithFields(log.Fields{
780 "IntfId": o.PonPortID,
781 "OnuId": o.ID,
782 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700783 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700784 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800785 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700786
787 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
788 o.PonPort.removeAllocId(o.SerialNumber)
789 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800790 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800791 case omci.MibUploadRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700792 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800793 case omci.MibUploadNextRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700794 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800795 case omci.GetRequestType:
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700796 onuDown := o.AdminLockState == 1
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700797 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId,
798 o.CommittedImageEntityId, o.StandbyImageVersion, o.ActiveImageVersion, o.CommittedImageVersion, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800799 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800800 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700801 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800802 switch msgObj.EntityClass {
803 case me.PhysicalPathTerminationPointEthernetUniClassID:
804 // if we're Setting a PPTP state
Matteo Scandolo8a574812021-05-20 15:18:53 -0700805 // we need to send the appropriate alarm (handled in the UNI struct)
806 uni, err := o.FindUniByEntityId(msgObj.EntityInstance)
807 if err != nil {
808 onuLogger.Error(err)
809 success = false
810 } else {
811 // 1 locks the UNI, 0 unlocks it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800812 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700813 var err error
Himani Chawla13b1ee02021-03-15 01:43:53 +0530814 if adminState == 1 {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700815 err = uni.Disable()
Girish Gowdra996d81e2021-04-21 16:16:27 -0700816 } else {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700817 err = uni.Enable()
Himani Chawla13b1ee02021-03-15 01:43:53 +0530818 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700819 if err != nil {
820 onuLogger.WithFields(log.Fields{
821 "IntfId": o.PonPortID,
822 "OnuId": o.ID,
823 "UniMeId": uni.MeId,
824 "UniId": uni.ID,
825 "SerialNumber": o.Sn(),
826 "Err": err.Error(),
827 }).Warn("cannot-change-uni-status")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800828 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800829 }
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700830 case me.OnuGClassID:
831 o.AdminLockState = msgObj.Attributes["AdministrativeState"].(uint8)
832 onuLogger.WithFields(log.Fields{
833 "IntfId": o.PonPortID,
834 "OnuId": o.ID,
835 "SerialNumber": o.Sn(),
836 "AdminLockState": o.AdminLockState,
837 }).Debug("set-onu-admin-lock-state")
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800838 case me.TContClassID:
839 allocId := msgObj.Attributes["AllocId"].(uint16)
840
841 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
842 // otherwise we are adding it
843 if allocId == 255 || allocId == 65535 {
844 onuLogger.WithFields(log.Fields{
845 "IntfId": o.PonPortID,
846 "OnuId": o.ID,
847 "TContId": msgObj.EntityInstance,
848 "AllocId": allocId,
849 "SerialNumber": o.Sn(),
850 }).Trace("freeing-alloc-id-via-omci")
851 o.PonPort.removeAllocId(o.SerialNumber)
852 } else {
853 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
854 onuLogger.WithFields(log.Fields{
855 "IntfId": o.PonPortID,
856 "OnuId": o.ID,
857 "AllocId": allocId,
858 "SerialNumber": o.Sn(),
859 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
860 success = false
861 } else {
862 onuLogger.WithFields(log.Fields{
863 "IntfId": o.PonPortID,
864 "OnuId": o.ID,
865 "TContId": msgObj.EntityInstance,
866 "AllocId": allocId,
867 "SerialNumber": o.Sn(),
868 }).Trace("storing-alloc-id-via-omci")
869 o.PonPort.storeAllocId(allocId, o.SerialNumber)
870 }
871 }
872
873 }
874
875 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700876 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800877 o.MibDataSync++
878 }
879 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700880 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800881 }
882 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800883 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
884 var used bool
885 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700886 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800887 if err == nil {
888 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700889 // GemPort 4069 is reserved for multicast and shared across ONUs
890 if msgObj.EntityInstance != 4069 {
891 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
892 onuLogger.WithFields(log.Fields{
893 "IntfId": o.PonPortID,
894 "OnuId": o.ID,
895 "GemPortId": msgObj.EntityInstance,
896 "SerialNumber": o.Sn(),
897 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
898 } else {
899 onuLogger.WithFields(log.Fields{
900 "IntfId": o.PonPortID,
901 "OnuId": o.ID,
902 "GemPortId": msgObj.EntityInstance,
903 "SerialNumber": o.Sn(),
904 }).Trace("storing-gem-port-id-via-omci")
905 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
906 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800907 }
908 }
909 }
910
911 // if the gemPort is valid then increment the MDS and return a successful response
912 // otherwise fail the request
913 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
914 // validation this check will need to be rewritten
915 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700916 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800917 o.MibDataSync++
918 }
919 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700920 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800921 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800922 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700923 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800924 if err == nil {
925 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
926 onuLogger.WithFields(log.Fields{
927 "IntfId": o.PonPortID,
928 "OnuId": o.ID,
929 "GemPortId": msgObj.EntityInstance,
930 "SerialNumber": o.Sn(),
931 }).Trace("freeing-gem-port-id-via-omci")
932 o.PonPort.removeGemPort(msgObj.EntityInstance)
933 }
934 }
935
Matteo Scandolob5913142021-03-19 16:10:18 -0700936 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800937 o.MibDataSync++
938 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800939 case omci.RebootRequestType:
940
Matteo Scandolob5913142021-03-19 16:10:18 -0700941 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800942
943 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800944 // we run this in a separate goroutine so that
945 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800946 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800947 if err := o.Reboot(10 * time.Second); err != nil {
948 log.WithFields(log.Fields{
949 "IntfId": o.PonPortID,
950 "OnuId": o.ID,
951 "SerialNumber": o.Sn(),
952 "err": err,
953 }).Error("cannot-reboot-onu-after-omci-reboot-request")
954 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800955 }()
956 case omci.TestRequestType:
Girish Gowdra161d27a2021-05-05 12:01:44 -0700957 var classID me.ClassID
958 var omciResult me.Results
959 var instID uint16
960 responsePkt, errResp, classID, instID, omciResult = omcilib.CreateTestResponse(msg.OmciPkt, msg.OmciMsg)
961 // Send TestResult only in case the TestResponse omci result code is me.Success
962 if responsePkt != nil && errResp == nil && omciResult == me.Success {
963 if testResultPkt, err := omcilib.CreateTestResult(classID, instID, msg.OmciMsg.TransactionID); err == nil {
964 // send test results asynchronously
965 go func() {
966 // Send test results after a second to emulate async behavior
967 time.Sleep(1 * time.Second)
968 if testResultPkt != nil {
969 if err := o.sendOmciIndication(testResultPkt, msg.OmciMsg.TransactionID, stream); err != nil {
970 onuLogger.WithFields(log.Fields{
971 "IntfId": o.PonPortID,
972 "SerialNumber": o.Sn(),
973 "omciPacket": testResultPkt,
974 "msg.OmciMsgType": msg.OmciMsg.MessageType,
975 "transCorrId": msg.OmciMsg.TransactionID,
976 }).Errorf("failed-to-send-omci-message: %v", err)
977 }
978 }
979 }()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800980 }
981 }
Girish Gowdraa539f522021-02-15 23:00:45 -0800982 case omci.SynchronizeTimeRequestType:
983 // MDS counter increment is not required for this message type
Matteo Scandolob5913142021-03-19 16:10:18 -0700984 responsePkt, _ = omcilib.CreateSyncTimeResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -0800985 case omci.StartSoftwareDownloadRequestType:
986
987 o.ImageSoftwareReceivedSections = 0
Himani Chawla4ff5fab2021-11-09 19:19:29 +0530988 o.ImageSectionData = []byte{}
Matteo Scandolob5913142021-03-19 16:10:18 -0700989 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
Matteo Scandolocedde462021-03-09 17:37:16 -0800990
Matteo Scandolob5913142021-03-19 16:10:18 -0700991 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -0800992 o.MibDataSync++
993 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
994 onuLogger.WithFields(log.Fields{
995 "OnuId": o.ID,
996 "IntfId": o.PonPortID,
997 "OnuSn": o.Sn(),
998 "Err": err.Error(),
999 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
1000 }
1001 } else {
1002 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001003 "OmciMsgType": msg.OmciMsg.MessageType,
1004 "TransCorrId": msg.OmciMsg.TransactionID,
1005 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001006 "IntfId": o.PonPortID,
1007 "SerialNumber": o.Sn(),
1008 }).Error("error-while-processing-start-software-download-request")
1009 }
1010 case omci.DownloadSectionRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001011 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001012 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001013 "OmciMsgType": msg.OmciMsg.MessageType,
1014 "TransCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001015 "EntityInstance": msgObj.EntityInstance,
1016 "SectionNumber": msgObj.SectionNumber,
1017 "SectionData": msgObj.SectionData,
1018 }).Trace("received-download-section-request")
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001019 //Extracting the first 14 bytes to use as a version for this image.
1020 if o.ImageSoftwareReceivedSections == 0 {
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001021 o.InDownloadImageVersion = string(msgObj.SectionData[0:14])
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001022 }
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301023 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
Matteo Scandolocedde462021-03-09 17:37:16 -08001024 o.ImageSoftwareReceivedSections++
1025 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1026 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1027 onuLogger.WithFields(log.Fields{
1028 "OnuId": o.ID,
1029 "IntfId": o.PonPortID,
1030 "OnuSn": o.Sn(),
1031 "Err": err.Error(),
1032 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1033 }
1034 }
1035 }
1036 case omci.DownloadSectionRequestWithResponseType:
1037 // NOTE we only need to respond if an ACK is requested
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301038 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001039 onuLogger.WithFields(log.Fields{
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301040 "OmciMsgType": msg.OmciMsg.MessageType,
1041 "TransCorrId": msg.OmciMsg.TransactionID,
1042 "EntityInstance": msgObj.EntityInstance,
1043 "SectionNumber": msgObj.SectionNumber,
1044 "SectionData": msgObj.SectionData,
1045 }).Trace("received-download-section-request-with-response-type")
1046 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
1047 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1048
1049 if errResp != nil {
1050 onuLogger.WithFields(log.Fields{
1051 "OmciMsgType": msg.OmciMsg.MessageType,
1052 "TransCorrId": msg.OmciMsg.TransactionID,
1053 "Err": errResp.Error(),
1054 "IntfId": o.PonPortID,
1055 "SerialNumber": o.Sn(),
1056 }).Error("error-while-processing-create-download-section-response")
1057 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
1058 }
1059 o.ImageSoftwareReceivedSections++
Matteo Scandolocedde462021-03-09 17:37:16 -08001060 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001061 case omci.EndSoftwareDownloadRequestType:
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001062 success := o.handleEndSoftwareDownloadRequest(msg)
Matteo Scandolocedde462021-03-09 17:37:16 -08001063
Matteo Scandolocedde462021-03-09 17:37:16 -08001064 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001065 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001066 o.MibDataSync++
1067 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1068 onuLogger.WithFields(log.Fields{
1069 "OnuId": o.ID,
1070 "IntfId": o.PonPortID,
1071 "OnuSn": o.Sn(),
1072 "Err": err.Error(),
1073 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1074 }
1075 } else {
1076 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001077 "OmciMsgType": msg.OmciMsg.MessageType,
1078 "TransCorrId": msg.OmciMsg.TransactionID,
1079 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001080 "IntfId": o.PonPortID,
1081 "SerialNumber": o.Sn(),
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001082 }).Error("error-while-responding-to-end-software-download-request")
Matteo Scandolocedde462021-03-09 17:37:16 -08001083 }
1084 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001085 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001086 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1087 onuLogger.WithFields(log.Fields{
1088 "OnuId": o.ID,
1089 "IntfId": o.PonPortID,
1090 "OnuSn": o.Sn(),
1091 "Err": err.Error(),
1092 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1093 }
1094 }
1095 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001096 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001097 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001098 o.MibDataSync++
1099 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1100 onuLogger.WithFields(log.Fields{
1101 "OnuId": o.ID,
1102 "IntfId": o.PonPortID,
1103 "OnuSn": o.Sn(),
1104 "Err": err.Error(),
1105 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1106 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001107 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001108 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001109 previousActiveImage := o.ActiveImageVersion
1110 o.ActiveImageVersion = o.StandbyImageVersion
1111 o.StandbyImageVersion = previousActiveImage
Matteo Scandolocedde462021-03-09 17:37:16 -08001112 } else {
1113 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1114 }
1115 onuLogger.WithFields(log.Fields{
1116 "OnuId": o.ID,
1117 "IntfId": o.PonPortID,
1118 "OnuSn": o.Sn(),
1119 "ActiveImageEntityId": o.ActiveImageEntityId,
1120 "CommittedImageEntityId": o.CommittedImageEntityId,
1121 }).Info("onu-software-image-activated")
1122
1123 // powercycle the ONU
1124 // we run this in a separate goroutine so that
1125 // the ActivateSoftwareResponse is sent to VOLTHA
1126 // NOTE do we need to wait before rebooting?
1127 go func() {
1128 if err := o.Reboot(10 * time.Second); err != nil {
1129 log.WithFields(log.Fields{
1130 "IntfId": o.PonPortID,
1131 "OnuId": o.ID,
1132 "SerialNumber": o.Sn(),
1133 "err": err,
1134 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1135 }
1136 }()
1137 }
1138 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001139 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001140 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001141 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001142 // TODO validate that the image to commit is:
1143 // - active
1144 // - not already committed
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001145 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandolocedde462021-03-09 17:37:16 -08001146 o.CommittedImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001147 //committed becomes standby
1148 o.StandbyImageVersion = o.CommittedImageVersion
1149 o.CommittedImageVersion = o.ActiveImageVersion
Matteo Scandolocedde462021-03-09 17:37:16 -08001150 } else {
1151 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1152 }
1153 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1154 onuLogger.WithFields(log.Fields{
1155 "OnuId": o.ID,
1156 "IntfId": o.PonPortID,
1157 "OnuSn": o.Sn(),
1158 "Err": err.Error(),
1159 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1160 }
1161 onuLogger.WithFields(log.Fields{
1162 "OnuId": o.ID,
1163 "IntfId": o.PonPortID,
1164 "OnuSn": o.Sn(),
1165 "ActiveImageEntityId": o.ActiveImageEntityId,
1166 "CommittedImageEntityId": o.CommittedImageEntityId,
1167 }).Info("onu-software-image-committed")
1168 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301169 case omci.GetAllAlarmsRequestType:
1170 // Reset the alarm sequence number on receiving get all alarms request.
1171 o.onuAlarmsInfoLock.Lock()
1172 for key, alarmInfo := range o.onuAlarmsInfo {
1173 // reset the alarm sequence no
1174 alarmInfo.SequenceNo = 0
1175 o.onuAlarmsInfo[key] = alarmInfo
1176 }
1177 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001178 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301179 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001180 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301181 responsePkt = nil //Do not send any response for error case
1182 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001183 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001184 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001185 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1186 "omciPkt": msg.OmciPkt,
1187 "omciMsgType": msg.OmciMsg.MessageType,
1188 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001189 "IntfId": o.PonPortID,
1190 "SerialNumber": o.Sn(),
1191 }).Warnf("OMCI-message-not-supported")
1192 }
1193
1194 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001195 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001196 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001197 "IntfId": o.PonPortID,
1198 "SerialNumber": o.Sn(),
1199 "omciPacket": responsePkt,
1200 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1201 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001202 }).Errorf("failed-to-send-omci-message: %v", err)
1203 }
1204 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001205
Pragya Arya324337e2020-02-20 14:35:08 +05301206 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001207 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001208}
Pragya Arya324337e2020-02-20 14:35:08 +05301209
Matteo Scandolof9d43412021-01-12 11:11:34 -08001210// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1211func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1212 indication := &openolt.Indication_OmciInd{
1213 OmciInd: &openolt.OmciIndication{
1214 IntfId: o.PonPortID,
1215 OnuId: o.ID,
1216 Pkt: responsePkt,
1217 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001218 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001219 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1220 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001221 }
1222 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001223 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001224 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001225 "omciPacket": indication.OmciInd.Pkt,
1226 "transCorrId": txId,
1227 }).Trace("omci-message-sent")
1228 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001229}
1230
Matteo Scandolo8a574812021-05-20 15:18:53 -07001231// FindUniById retrieves a UNI by ID
1232func (o *Onu) FindUniById(uniID uint32) (*UniPort, error) {
1233 for _, u := range o.UniPorts {
1234 uni := u.(*UniPort)
1235 if uni.ID == uniID {
1236 return uni, nil
1237 }
Matteo Scandolo27428702019-10-11 16:21:16 -07001238 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001239 return nil, fmt.Errorf("cannot-find-uni-with-id-%d-on-onu-%s", uniID, o.Sn())
1240}
1241
1242// FindUniByEntityId retrieves a uni by MeID (the OMCI entity ID)
1243func (o *Onu) FindUniByEntityId(meId uint16) (*UniPort, error) {
1244 entityId := omcilib.EntityID{}.FromUint16(meId)
1245 for _, u := range o.UniPorts {
1246 uni := u.(*UniPort)
1247 if uni.MeId.Equals(entityId) {
1248 return uni, nil
1249 }
1250 }
1251 return nil, fmt.Errorf("cannot-find-uni-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
Matteo Scandolo27428702019-10-11 16:21:16 -07001252}
1253
William Kurkian0418bc82019-11-06 12:16:24 -05001254func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001255 onuLogger.WithFields(log.Fields{
1256 "IntfId": o.PonPortID,
1257 "OnuId": id,
1258 "SerialNumber": o.Sn(),
1259 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001260 o.ID = id
1261}
1262
Matteo Scandolof9d43412021-01-12 11:11:34 -08001263func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001264 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001265 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001266 "Cookie": msg.Flow.Cookie,
1267 "DstPort": msg.Flow.Classifier.DstPort,
1268 "FlowId": msg.Flow.FlowId,
1269 "FlowType": msg.Flow.FlowType,
1270 "GemportId": msg.Flow.GemportId,
1271 "InnerVlan": msg.Flow.Classifier.IVid,
1272 "IntfId": msg.Flow.AccessIntfId,
1273 "IpProto": msg.Flow.Classifier.IpProto,
1274 "OnuId": msg.Flow.OnuId,
1275 "OnuSn": o.Sn(),
1276 "OuterVlan": msg.Flow.Classifier.OVid,
1277 "PortNo": msg.Flow.PortNo,
1278 "SrcPort": msg.Flow.Classifier.SrcPort,
1279 "UniID": msg.Flow.UniId,
1280 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1281 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1282 "ClassifierIVid": msg.Flow.Classifier.IVid,
1283 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001284 "ReplicateFlow": msg.Flow.ReplicateFlow,
1285 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001286 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001287
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001288 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001289
1290 var gemPortId uint32
1291 if msg.Flow.ReplicateFlow {
1292 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1293 // first available gemport (we only need to send one packet)
1294 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1295 gemPortId = msg.Flow.PbitToGemport[0]
1296 } else {
1297 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1298 gemPortId = uint32(msg.Flow.GemportId)
1299 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001300
1301 uni, err := o.FindUniById(uint32(msg.Flow.UniId))
1302 if err != nil {
1303 onuLogger.WithFields(log.Fields{
1304 "IntfId": o.PonPortID,
1305 "OnuId": o.ID,
1306 "UniId": msg.Flow.UniId,
1307 "PortNo": msg.Flow.PortNo,
1308 "SerialNumber": o.Sn(),
1309 "FlowId": msg.Flow.FlowId,
1310 "FlowType": msg.Flow.FlowType,
1311 }).Error("cannot-find-uni-port-for-flow")
1312 }
1313
1314 uni.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
1315 uni.StorePortNo(msg.Flow.PortNo)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001316
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001317 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001318 uni.HandleAuth()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001319 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1320 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001321 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001322 uni.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001323 }
1324}
1325
Matteo Scandolof9d43412021-01-12 11:11:34 -08001326func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001327 onuLogger.WithFields(log.Fields{
1328 "IntfId": o.PonPortID,
1329 "OnuId": o.ID,
1330 "SerialNumber": o.Sn(),
1331 "FlowId": msg.Flow.FlowId,
1332 "FlowType": msg.Flow.FlowType,
1333 }).Debug("ONU receives FlowRemove")
1334
1335 for idx, flow := range o.FlowIds {
1336 // If the gemport is found, delete it from local cache.
1337 if flow == msg.Flow.FlowId {
1338 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1339 break
1340 }
1341 }
1342
1343 if len(o.FlowIds) == 0 {
1344 onuLogger.WithFields(log.Fields{
1345 "IntfId": o.PonPortID,
1346 "OnuId": o.ID,
1347 "SerialNumber": o.Sn(),
1348 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001349
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301350 // check if ONU delete is performed and
1351 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001352 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301353 close(o.Channel)
1354 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001355 }
1356}
1357
Matteo Scandolocedde462021-03-09 17:37:16 -08001358func (o *Onu) Reboot(timeout time.Duration) error {
1359 onuLogger.WithFields(log.Fields{
1360 "IntfId": o.PonPortID,
1361 "OnuId": o.ID,
1362 "SerialNumber": o.Sn(),
1363 }).Debug("shutting-down-onu")
1364 if err := o.HandleShutdownONU(); err != nil {
1365 return err
1366 }
1367 time.Sleep(timeout)
1368 onuLogger.WithFields(log.Fields{
1369 "IntfId": o.PonPortID,
1370 "OnuId": o.ID,
1371 "SerialNumber": o.Sn(),
1372 }).Debug("power-on-onu")
1373 if err := o.HandlePowerOnONU(); err != nil {
1374 return err
1375 }
1376 return nil
1377}
1378
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001379// returns true if the request is successful, false otherwise
1380func (o *Onu) handleEndSoftwareDownloadRequest(msg bbsim.OmciMessage) bool {
1381 msgObj, err := omcilib.ParseEndSoftwareDownloadRequest(msg.OmciPkt)
1382 if err != nil {
1383 onuLogger.WithFields(log.Fields{
1384 "OmciMsgType": msg.OmciMsg.MessageType,
1385 "TransCorrId": msg.OmciMsg.TransactionID,
1386 "Err": err.Error(),
1387 "IntfId": o.PonPortID,
1388 "SerialNumber": o.Sn(),
1389 }).Error("error-while-processing-end-software-download-request")
1390 return false
1391 }
1392
1393 onuLogger.WithFields(log.Fields{
1394 "OnuId": o.ID,
1395 "IntfId": o.PonPortID,
1396 "OnuSn": o.Sn(),
1397 "msgObj": msgObj,
1398 }).Trace("EndSoftwareDownloadRequest received message")
1399
1400 // if the image download is ongoing and we receive a message with
1401 // ImageSize = 0 and Crc = 4294967295 (0xFFFFFFFF) respond with success
1402 if o.ImageSoftwareReceivedSections > 0 &&
1403 msgObj.ImageSize == 0 &&
1404 msgObj.CRC32 == 4294967295 {
1405 o.ImageSoftwareReceivedSections = 0
1406 // NOTE potentially we may want to add a ONU state to reflect
1407 // the software download abort
1408 return true
1409 }
1410
1411 // In the startSoftwareDownload we get the image size and the window size.
1412 // We calculate how many DownloadSection we should receive and validate
1413 // that we got the correct amount when we receive this message
1414 // If the received sections are different from the expected sections
1415 // respond with failure
1416 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1417 onuLogger.WithFields(log.Fields{
1418 "OnuId": o.ID,
1419 "IntfId": o.PonPortID,
1420 "OnuSn": o.Sn(),
1421 "ExpectedSections": o.ImageSoftwareExpectedSections,
1422 "ReceivedSections": o.ImageSoftwareReceivedSections,
1423 }).Errorf("onu-did-not-receive-all-image-sections")
1424 return false
1425 }
1426
1427 // check the received CRC vs the computed CRC
1428 computedCRC := crc32a.Checksum(o.ImageSectionData[:int(msgObj.ImageSize)])
1429 //Convert the crc to network byte order
1430 var byteSlice = make([]byte, 4)
1431 binary.LittleEndian.PutUint32(byteSlice, computedCRC)
1432 computedCRC = binary.BigEndian.Uint32(byteSlice)
1433 if msgObj.CRC32 != computedCRC {
1434 onuLogger.WithFields(log.Fields{
1435 "OnuId": o.ID,
1436 "IntfId": o.PonPortID,
1437 "OnuSn": o.Sn(),
1438 "ReceivedCRC": msgObj.CRC32,
1439 "CalculatedCRC": computedCRC,
1440 }).Errorf("onu-image-crc-validation-failed")
1441 return false
1442 }
1443
1444 o.StandbyImageVersion = o.InDownloadImageVersion
1445 onuLogger.WithFields(log.Fields{
1446 "OnuId": o.ID,
1447 "IntfId": o.PonPortID,
1448 "OnuSn": o.Sn(),
1449 "StandbyVersion": o.StandbyImageVersion,
1450 }).Debug("onu-image-version-updated")
1451 return true
1452}
1453
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001454// BBR methods
1455
1456func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1457 omciMsg := openolt.OmciMsg{
1458 IntfId: intfId,
1459 OnuId: onuId,
1460 Pkt: pktBytes,
1461 }
1462
1463 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1464 log.WithFields(log.Fields{
1465 "IntfId": intfId,
1466 "OnuId": onuId,
1467 "SerialNumber": common.OnuSnToString(sn),
1468 "Pkt": omciMsg.Pkt,
1469 }).Fatalf("Failed to send MIB Reset")
1470 }
1471 log.WithFields(log.Fields{
1472 "IntfId": intfId,
1473 "OnuId": onuId,
1474 "SerialNumber": common.OnuSnToString(sn),
1475 "Pkt": omciMsg.Pkt,
1476 }).Tracef("Sent OMCI message %s", msgType)
1477}
1478
1479func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1480 var next uint16
1481 if len(highPriority) > 0 && highPriority[0] {
1482 next = onu.hpTid
1483 onu.hpTid += 1
1484 if onu.hpTid < 0x8000 {
1485 onu.hpTid = 0x8000
1486 }
1487 } else {
1488 next = onu.tid
1489 onu.tid += 1
1490 if onu.tid >= 0x8000 {
1491 onu.tid = 1
1492 }
1493 }
1494 return next
1495}
1496
1497// TODO move this method in responders/omcisim
Matteo Scandolo8a574812021-05-20 15:18:53 -07001498// StartOmci is called in BBR to start the OMCI state machine
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001499func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1500 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1501 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1502}
1503
Matteo Scandolof9d43412021-01-12 11:11:34 -08001504// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1505func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1506
1507 // we need to encode the packet in HEX
1508 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1509 hex.Encode(pkt, msg.OmciInd.Pkt)
1510 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1511 if err != nil {
1512 log.WithFields(log.Fields{
1513 "IntfId": o.PonPortID,
1514 "SerialNumber": o.Sn(),
1515 "omciPacket": msg.OmciInd.Pkt,
1516 }).Error("BBR Cannot parse OMCI packet")
1517 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001518
1519 log.WithFields(log.Fields{
1520 "IntfId": msg.OmciInd.IntfId,
1521 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001522 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001523 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001524 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301525 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001526 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001527 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001528 log.WithFields(log.Fields{
1529 "IntfId": msg.OmciInd.IntfId,
1530 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001531 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001532 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001533 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001534 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001535 case omci.MibResetResponseType:
1536 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1537 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1538 case omci.MibUploadResponseType:
1539 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1540 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1541 case omci.MibUploadNextResponseType:
1542 o.seqNumber++
Matteo Scandolo8a574812021-05-20 15:18:53 -07001543 // once the mibUpload is complete send a SetRequest for the PPTP to enable the UNI
1544 // NOTE that in BBR we only enable the first UNI
1545 if o.seqNumber == o.MibDb.NumberOfCommands {
1546 meId := omcilib.GenerateUniPortEntityId(1)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001547
Matteo Scandolo8a574812021-05-20 15:18:53 -07001548 meParams := me.ParamData{
1549 EntityID: meId.ToUint16(),
1550 Attributes: me.AttributeValueMap{"AdministrativeState": 0},
1551 }
1552 managedEntity, omciError := me.NewPhysicalPathTerminationPointEthernetUni(meParams)
1553 if omciError.GetError() != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001554 onuLogger.WithFields(log.Fields{
1555 "OnuId": o.ID,
1556 "IntfId": o.PonPortID,
1557 "OnuSn": o.Sn(),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001558 }).Fatal(omciError.GetError())
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001559 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001560
1561 setPPtp, _ := omcilib.CreateSetRequest(managedEntity, 1)
1562 sendOmciMsg(setPPtp, o.PonPortID, o.ID, o.SerialNumber, "setRquest", client)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001563 } else {
1564 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1565 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001566 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001567 case omci.SetResponseType:
1568 // once we set the PPTP to active we can start sending flows
1569
1570 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
1571 onuLogger.WithFields(log.Fields{
1572 "OnuId": o.ID,
1573 "IntfId": o.PonPortID,
1574 "OnuSn": o.Sn(),
1575 }).Errorf("Error while transitioning ONU State %v", err)
1576 }
1577 case omci.AlarmNotificationType:
1578 log.Info("bbr-received-alarm")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001579 }
1580}
1581
1582func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1583
1584 classifierProto := openolt.Classifier{
1585 EthType: uint32(layers.EthernetTypeEAPOL),
1586 OVid: 4091,
1587 }
1588
1589 actionProto := openolt.Action{}
1590
1591 downstreamFlow := openolt.Flow{
1592 AccessIntfId: int32(o.PonPortID),
1593 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001594 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001595 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001596 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001597 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001598 Classifier: &classifierProto,
1599 Action: &actionProto,
1600 Priority: int32(100),
1601 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001602 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1603 // AllocId and GemPorts need to be unique per PON
1604 // for now use the ONU-ID, will need to change once we support multiple UNIs
1605 AllocId: int32(o.ID),
1606 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001607 }
1608
1609 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1610 log.WithFields(log.Fields{
1611 "IntfId": o.PonPortID,
1612 "OnuId": o.ID,
1613 "FlowId": downstreamFlow.FlowId,
1614 "PortNo": downstreamFlow.PortNo,
1615 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001616 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001617 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001618 }
1619 log.WithFields(log.Fields{
1620 "IntfId": o.PonPortID,
1621 "OnuId": o.ID,
1622 "FlowId": downstreamFlow.FlowId,
1623 "PortNo": downstreamFlow.PortNo,
1624 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1625 }).Info("Sent EAPOL Flow")
1626}
1627
1628func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001629
Matteo Scandolo8a574812021-05-20 15:18:53 -07001630 // BBR only works with a single UNI and a single service (ATT HSIA)
1631 hsia := o.UniPorts[0].(*UniPort).Services[0].(*Service)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001632 classifierProto := openolt.Classifier{
1633 EthType: uint32(layers.EthernetTypeIPv4),
1634 SrcPort: uint32(68),
1635 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001636 OVid: uint32(hsia.CTag),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001637 OPbits: 255,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001638 }
1639
1640 actionProto := openolt.Action{}
1641
1642 downstreamFlow := openolt.Flow{
1643 AccessIntfId: int32(o.PonPortID),
1644 OnuId: int32(o.ID),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001645 UniId: int32(0), // BBR only supports a single UNI
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001646 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001647 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001648 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001649 Classifier: &classifierProto,
1650 Action: &actionProto,
1651 Priority: int32(100),
1652 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001653 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1654 // AllocId and GemPorts need to be unique per PON
1655 // for now use the ONU-ID, will need to change once we support multiple UNIs
1656 AllocId: int32(o.ID),
1657 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001658 }
1659
1660 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1661 log.WithFields(log.Fields{
1662 "IntfId": o.PonPortID,
1663 "OnuId": o.ID,
1664 "FlowId": downstreamFlow.FlowId,
1665 "PortNo": downstreamFlow.PortNo,
1666 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001667 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001668 }).Fatalf("Failed to send DHCP Flow")
1669 }
1670 log.WithFields(log.Fields{
1671 "IntfId": o.PonPortID,
1672 "OnuId": o.ID,
1673 "FlowId": downstreamFlow.FlowId,
1674 "PortNo": downstreamFlow.PortNo,
1675 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1676 }).Info("Sent DHCP Flow")
1677}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301678
1679// DeleteFlow method search and delete flowKey from the onu flows slice
1680func (onu *Onu) DeleteFlow(key FlowKey) {
1681 for pos, flowKey := range onu.Flows {
1682 if flowKey == key {
1683 // delete the flowKey by shifting all flowKeys by one
1684 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1685 t := make([]FlowKey, len(onu.Flows))
1686 copy(t, onu.Flows)
1687 onu.Flows = t
1688 break
1689 }
1690 }
1691}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301692
1693func (onu *Onu) ReDiscoverOnu() {
1694 // Wait for few seconds to be sure of the cleanup
1695 time.Sleep(5 * time.Second)
1696
1697 onuLogger.WithFields(log.Fields{
1698 "IntfId": onu.PonPortID,
1699 "OnuId": onu.ID,
1700 "OnuSn": onu.Sn(),
1701 }).Debug("Send ONU Re-Discovery")
1702
1703 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001704 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301705 log.WithFields(log.Fields{
1706 "IntfId": onu.PonPortID,
1707 "OnuSn": onu.Sn(),
1708 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001709 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301710 }
1711
Matteo Scandolocedde462021-03-09 17:37:16 -08001712 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301713 log.WithFields(log.Fields{
1714 "IntfId": onu.PonPortID,
1715 "OnuSn": onu.Sn(),
1716 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001717 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301718 }
1719}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001720
Matteo Scandolo8a574812021-05-20 15:18:53 -07001721// deprecated, delegate this to the uniPort
Matteo Scandolo4a036262020-08-17 15:56:13 -07001722func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001723 // FIXME is there a better way to avoid this loop?
1724 for _, u := range onu.UniPorts {
1725 uni := u.(*UniPort)
1726 for _, s := range uni.Services {
1727 service := s.(*Service)
1728 if service.HwAddress.String() == macAddress.String() {
1729 return service, nil
1730 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001731 }
1732 }
1733 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1734}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301735
Matteo Scandolo8a574812021-05-20 15:18:53 -07001736func (onu *Onu) findUniByPortNo(portNo uint32) (*UniPort, error) {
1737 for _, u := range onu.UniPorts {
1738 uni := u.(*UniPort)
1739 if uni.PortNo == portNo {
1740 return uni, nil
1741 }
1742 }
1743 return nil, fmt.Errorf("cannot-find-uni-with-port-no-%d", portNo)
1744}
1745
Himani Chawla13b1ee02021-03-15 01:43:53 +05301746func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1747 switch alarmType {
1748 case "ONU_ALARM_LOS":
1749 msg := bbsim.Message{
1750 Type: bbsim.UniStatusAlarm,
1751 Data: bbsim.UniStatusAlarmMessage{
1752 OnuSN: o.SerialNumber,
1753 OnuID: o.ID,
1754 EntityID: 257,
1755 RaiseOMCIAlarm: raiseOMCIAlarm,
1756 },
1757 }
1758 o.Channel <- msg
1759 }
1760
1761}
1762
1763func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1764 o.onuAlarmsInfoLock.Lock()
1765 defer o.onuAlarmsInfoLock.Unlock()
1766 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1767 if alarmInfo.SequenceNo == 255 {
1768 alarmInfo.SequenceNo = 1
1769 } else {
1770 alarmInfo.SequenceNo++
1771 }
1772 o.onuAlarmsInfo[key] = alarmInfo
1773 return alarmInfo.SequenceNo
1774 } else {
1775 // This is the first time alarm notification message is being sent
1776 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1777 SequenceNo: 1,
1778 }
1779 return 1
1780 }
1781}
Elia Battistonfe017662022-01-05 11:43:16 +01001782
1783func (o *Onu) InvalidateMibDataSync() {
1784 rand.Seed(time.Now().UnixNano())
1785 r := uint8(rand.Intn(10) + 1)
1786
1787 o.MibDataSync += r
1788
1789 // Since MibDataSync is a uint8, summing to it will never
1790 // result in a value higher than 255, but could be 0
1791 if o.MibDataSync == 0 {
1792 o.MibDataSync++
1793 }
1794}