blob: cfc7099cf975e1304679a3561751d7b8a3fdcf8e [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
Elia Battistonac63b112022-01-12 18:40:49 +0100111 UniPorts []UniPortIf
112 PotsPorts []PotsPortIf
113 Flows []FlowKey
114 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700115
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700116 OperState *fsm.FSM
117 SerialNumber *openolt.SerialNumber
118
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700119 AdminLockState uint8 // 0 is enabled, 1 is disabled.
120
Matteo Scandolof9d43412021-01-12 11:11:34 -0800121 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700122
123 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800124 MibDataSync uint8
125 ImageSoftwareExpectedSections int
126 ImageSoftwareReceivedSections int
127 ActiveImageEntityId uint16
128 CommittedImageEntityId uint16
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700129 StandbyImageVersion string
130 ActiveImageVersion string
Matteo Scandolo76f6b892021-11-15 16:13:06 -0800131 InDownloadImageVersion string
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700132 CommittedImageVersion string
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000133 OmciResponseRate uint8
134 OmciMsgCounter uint8
Himani Chawla4ff5fab2021-11-09 19:19:29 +0530135 ImageSectionData []byte
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800136
137 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700138 tid uint16
139 hpTid uint16
140 seqNumber uint16
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700141 MibDb *omcilib.MibDb
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700142
Anand S Katti09541352020-01-29 15:54:01 +0530143 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
144 TrafficSchedulers *tech_profile.TrafficSchedulers
Himani Chawla13b1ee02021-03-15 01:43:53 +0530145 onuAlarmsInfoLock sync.RWMutex
146 onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700147}
148
Matteo Scandolo99f18462019-10-28 14:14:28 -0700149func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700150 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700151}
152
Matteo Scandolo8a574812021-05-20 15:18:53 -0700153func 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 -0700154
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700155 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800156 ID: id,
157 PonPortID: pon.ID,
158 PonPort: pon,
Matteo Scandolocedde462021-03-09 17:37:16 -0800159 tid: 0x1,
160 hpTid: 0x8000,
161 seqNumber: 0,
162 DoneChannel: make(chan bool, 1),
163 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
164 Flows: []FlowKey{},
165 DiscoveryDelay: delay,
166 MibDataSync: 0,
167 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
168 ImageSoftwareReceivedSections: 0,
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700169 //TODO this needs reworking, it's always 0 or 1, possibly base all on the version
170 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
171 CommittedImageEntityId: 0,
172 StandbyImageVersion: "BBSM_IMG_00000",
173 ActiveImageVersion: "BBSM_IMG_00001",
174 CommittedImageVersion: "BBSM_IMG_00001",
175 OmciResponseRate: olt.OmciResponseRate,
176 OmciMsgCounter: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700177 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800178 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700179 // NOTE this state machine is used to track the operational
180 // state as requested by VOLTHA
181 o.OperState = getOperStateFSM(func(e *fsm.Event) {
182 onuLogger.WithFields(log.Fields{
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700183 "OnuId": o.ID,
184 "IntfId": o.PonPortID,
185 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700186 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
187 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530188 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700189 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
190 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800191 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700192 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700193 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800194 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
195 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
196 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100197 // 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 -0800198 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530199 // 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 +0200200 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted, OnuStateImageDownloadComplete}, Dst: OnuStatePonDisabled},
Matteo Scandolocedde462021-03-09 17:37:16 -0800201 // Software Image Download related states
Matteo Scandolo9f4bf4f2021-06-22 09:41:02 +0200202 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateImageDownloadStarted},
Matteo Scandolocedde462021-03-09 17:37:16 -0800203 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
204 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
205 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
206 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
207 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700208 // BBR States
209 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800210 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
211 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700212 },
213 fsm.Callbacks{
214 "enter_state": func(e *fsm.Event) {
215 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700216 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700217 fmt.Sprintf("enter_%s", OnuStateInitialized): func(e *fsm.Event) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100218 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800219 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800220
Matteo Scandolocedde462021-03-09 17:37:16 -0800221 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800222 onuLogger.WithFields(log.Fields{
223 "OnuId": o.ID,
224 "IntfId": o.PonPortID,
225 "OnuSn": o.Sn(),
226 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
227 }
228
Pragya Arya1cbefa42020-01-13 12:15:29 +0530229 if !isMock {
230 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700231 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530232 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100233 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700234 fmt.Sprintf("enter_%s", OnuStateDiscovered): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800235 msg := bbsim.Message{
236 Type: bbsim.OnuDiscIndication,
237 Data: bbsim.OnuDiscIndicationMessage{
238 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100239 },
240 }
241 o.Channel <- msg
242 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700243 fmt.Sprintf("enter_%s", OnuStateEnabled): func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800244
245 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
246 onuLogger.WithFields(log.Fields{
247 "IntfId": o.PonPortID,
248 "OnuId": o.ID,
249 "SerialNumber": o.Sn(),
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700250 }).Errorf("onu-id-duplicated-with-%s", common.OnuSnToString(sn))
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800251 return
252 } else {
253 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
254 }
255
Matteo Scandolof9d43412021-01-12 11:11:34 -0800256 msg := bbsim.Message{
257 Type: bbsim.OnuIndication,
258 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700259 OnuSN: o.SerialNumber,
260 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800261 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700262 },
263 }
264 o.Channel <- msg
265 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700266 fmt.Sprintf("enter_%s", OnuStateDisabled): func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700267
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700268 o.cleanupOnuState()
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700269
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700270 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800271 if err := o.OperState.Event("disable"); err != nil {
272 onuLogger.WithFields(log.Fields{
273 "OnuId": o.ID,
274 "IntfId": o.PonPortID,
275 "OnuSn": o.Sn(),
276 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
277 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700278 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800279 msg := bbsim.Message{
280 Type: bbsim.OnuIndication,
281 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700282 OnuSN: o.SerialNumber,
283 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800284 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700285 },
286 }
287 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530288
Matteo Scandolo8a574812021-05-20 15:18:53 -0700289 // disable the UNI ports
290 for _, uni := range o.UniPorts {
291 _ = uni.Disable()
292 }
293
Elia Battistonac63b112022-01-12 18:40:49 +0100294 // disable the POTS UNI ports
295 for _, pots := range o.PotsPorts {
296 _ = pots.Disable()
297 }
298
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530299 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100300 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolo8a574812021-05-20 15:18:53 -0700301 // NOTE may need to wait for the UNIs to be down too before shutting down the channel
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530302 if len(o.FlowIds) == 0 {
303 close(o.Channel)
304 }
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700305 },
306 fmt.Sprintf("enter_%s", OnuStatePonDisabled): func(event *fsm.Event) {
307 o.cleanupOnuState()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700308 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700309 // BBR states
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700310 fmt.Sprintf("enter_%s", BbrOnuStateEapolFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800311 msg := bbsim.Message{
312 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700313 }
314 o.Channel <- msg
315 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700316 fmt.Sprintf("enter_%s", BbrOnuStateDhcpFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800317 msg := bbsim.Message{
318 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700319 }
320 o.Channel <- msg
321 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700322 },
323 )
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700324 onuLogger.WithFields(log.Fields{
Elia Battistonac63b112022-01-12 18:40:49 +0100325 "OnuId": o.ID,
326 "IntfId": o.PonPortID,
327 "OnuSn": o.Sn(),
328 "NumUni": olt.NumUni,
329 "NumPots": olt.NumPots,
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700330 }).Debug("creating-uni-ports")
Elia Battistonac63b112022-01-12 18:40:49 +0100331
332 // create Ethernet UNIs
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700333 for i := 0; i < olt.NumUni; i++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700334 uni, err := NewUniPort(uint32(i), &o, nextCtag, nextStag)
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700335 if err != nil {
336 onuLogger.WithFields(log.Fields{
337 "OnuId": o.ID,
338 "IntfId": o.PonPortID,
339 "OnuSn": o.Sn(),
340 "Err": err,
341 }).Fatal("cannot-create-uni-port")
342 }
343 o.UniPorts = append(o.UniPorts, uni)
344 }
Elia Battistonac63b112022-01-12 18:40:49 +0100345 // create POTS UNIs, with progressive IDs
346 for i := olt.NumUni; i < (olt.NumUni + olt.NumPots); i++ {
347 pots, err := NewPotsPort(uint32(i), &o)
348 if err != nil {
349 onuLogger.WithFields(log.Fields{
350 "OnuId": o.ID,
351 "IntfId": o.PonPortID,
352 "OnuSn": o.Sn(),
353 "Err": err,
354 }).Fatal("cannot-create-pots-port")
355 }
356 o.PotsPorts = append(o.PotsPorts, pots)
357 }
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700358
Elia Battistonac63b112022-01-12 18:40:49 +0100359 mibDb, err := omcilib.GenerateMibDatabase(len(o.UniPorts), len(o.PotsPorts))
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700360 if err != nil {
361 onuLogger.WithFields(log.Fields{
362 "OnuId": o.ID,
363 "IntfId": o.PonPortID,
364 "OnuSn": o.Sn(),
365 }).Fatal("cannot-generate-mibdb-for-onu")
366 }
367 o.MibDb = mibDb
368
Matteo Scandolo27428702019-10-11 16:21:16 -0700369 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700370}
371
William Kurkian0418bc82019-11-06 12:16:24 -0500372func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700373 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700374 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700375 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700376 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700377 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
378}
379
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700380// cleanupOnuState this method is to clean the local state when the ONU is disabled
381func (o *Onu) cleanupOnuState() {
382 // clean the ONU state
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700383 o.Flows = []FlowKey{}
384 o.PonPort.removeOnuId(o.ID)
385 o.PonPort.removeAllocId(o.SerialNumber)
386 o.PonPort.removeGemPortBySn(o.SerialNumber)
387
388 o.onuAlarmsInfoLock.Lock()
389 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
390 o.onuAlarmsInfoLock.Unlock()
391}
392
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100393// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000394func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700395 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100396 "onuID": o.ID,
397 "onuSN": o.Sn(),
398 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700399 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100400 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700401
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700402 defer onuLogger.WithFields(log.Fields{
403 "onuID": o.ID,
404 "onuSN": o.Sn(),
405 "stream": stream,
406 }).Debug("Stopped handling ONU Indication Channel")
407
David Bainbridge103cf022019-12-16 20:11:35 +0000408loop:
409 for {
410 select {
411 case <-ctx.Done():
412 onuLogger.WithFields(log.Fields{
413 "onuID": o.ID,
414 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700415 }).Debug("ONU message handling canceled via context")
416 break loop
417 case <-stream.Context().Done():
418 onuLogger.WithFields(log.Fields{
419 "onuID": o.ID,
420 "onuSN": o.Sn(),
421 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000422 break loop
423 case message, ok := <-o.Channel:
424 if !ok || ctx.Err() != nil {
425 onuLogger.WithFields(log.Fields{
426 "onuID": o.ID,
427 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700428 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000429 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700430 }
David Bainbridge103cf022019-12-16 20:11:35 +0000431 onuLogger.WithFields(log.Fields{
432 "onuID": o.ID,
433 "onuSN": o.Sn(),
434 "messageType": message.Type,
435 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700436
David Bainbridge103cf022019-12-16 20:11:35 +0000437 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800438 case bbsim.OnuDiscIndication:
439 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000440 // 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 +0530441 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000442 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800443 case bbsim.OnuIndication:
444 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000445 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800446 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800447 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800448 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200449 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800450 case bbsim.UniStatusAlarm:
451 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530452 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
453 MeInstance: msg.EntityID,
454 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
455 }
456 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
457 o.onuAlarmsInfoLock.Lock()
458 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
459 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
460 if pkt != nil { //pkt will be nil if we are unable to create the alarm
461 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
462 onuLogger.WithFields(log.Fields{
463 "IntfId": o.PonPortID,
464 "SerialNumber": o.Sn(),
465 "omciPacket": pkt,
466 "adminState": msg.AdminState,
467 "entityID": msg.EntityID,
468 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
469 alarmInfo.SequenceNo--
470 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800471 onuLogger.WithFields(log.Fields{
472 "IntfId": o.PonPortID,
473 "SerialNumber": o.Sn(),
474 "omciPacket": pkt,
475 "adminState": msg.AdminState,
476 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530477 }).Trace("UNI-Link-alarm-sent")
478 if alarmBitMap == [28]byte{0} {
479 delete(o.onuAlarmsInfo, onuAlarmMapKey)
480 } else {
481 alarmInfo.AlarmBitMap = alarmBitMap
482 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
483 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800484 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530485 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800486 case bbsim.FlowAdd:
487 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700488 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800489 case bbsim.FlowRemoved:
490 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700491 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800492 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700493
Matteo Scandolof9d43412021-01-12 11:11:34 -0800494 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000495
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700496 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000497 "IntfId": msg.IntfId,
498 "OnuId": msg.OnuId,
499 "pktType": msg.Type,
500 }).Trace("Received OnuPacketOut Message")
501
Matteo Scandolo8a574812021-05-20 15:18:53 -0700502 uni, err := o.findUniByPortNo(msg.PortNo)
Matteo Scandolo618a6582020-09-09 12:21:29 -0700503
Matteo Scandolo8a574812021-05-20 15:18:53 -0700504 if err != nil {
505 onuLogger.WithFields(log.Fields{
506 "IntfId": msg.IntfId,
507 "OnuId": msg.OnuId,
508 "pktType": msg.Type,
509 "portNo": msg.PortNo,
510 "MacAddress": msg.MacAddress,
511 "Pkt": hex.EncodeToString(msg.Packet.Data()),
512 "OnuSn": o.Sn(),
513 }).Error("Cannot find Uni associated with packet")
514 return
David Bainbridge103cf022019-12-16 20:11:35 +0000515 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700516 uni.PacketCh <- msg
517 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800518 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000519 // NOTE we only receive BBR packets here.
520 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
521 // 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 -0800522 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000523
Matteo Scandolo8a574812021-05-20 15:18:53 -0700524 onuLogger.WithFields(log.Fields{
525 "IntfId": msg.IntfId,
526 "OnuId": msg.OnuId,
527 "PortNo": msg.PortNo,
528 "GemPortId": msg.GemPortId,
529 "pktType": msg.Type,
David Bainbridge103cf022019-12-16 20:11:35 +0000530 }).Trace("Received OnuPacketIn Message")
531
Matteo Scandolo8a574812021-05-20 15:18:53 -0700532 uni, err := o.findUniByPortNo(msg.PortNo)
533 if err != nil {
534 onuLogger.WithFields(log.Fields{
535 "IntfId": msg.IntfId,
536 "OnuId": msg.OnuId,
537 "PortNo": msg.PortNo,
538 "GemPortId": msg.GemPortId,
539 "pktType": msg.Type,
540 }).Error(err.Error())
541 }
542
543 // BBR has one service and one UNI
544 serviceId := uint32(0)
545 oltId := 0
David Bainbridge103cf022019-12-16 20:11:35 +0000546 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700547 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 +0000548 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700549 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000550 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800551 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800552 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800553 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
554 o.handleOmciResponse(msg, client)
555 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000556 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800557 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000558 o.sendDhcpFlow(client)
559 default:
560 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700561 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700562 }
563 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700564}
565
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800566func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700567 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700568 sn.VendorId = []byte("BBSM")
569 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700570 return sn
571}
572
Matteo Scandolof9d43412021-01-12 11:11:34 -0800573func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700574 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800575 IntfId: o.PonPortID,
576 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700577 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700578
Matteo Scandolo4747d292019-08-05 11:50:18 -0700579 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700580 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700581 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700582 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700583
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700584 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800585 "IntfId": o.PonPortID,
586 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700587 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700588 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800589 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800590
591 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
592 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800593 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800594 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800595 o.sendOnuDiscIndication(msg, stream)
596 }
597 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700598}
599
Matteo Scandolof9d43412021-01-12 11:11:34 -0800600func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800601 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
602 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700603
604 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700605 IntfId: o.PonPortID,
606 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700607 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700608 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700609 SerialNumber: o.SerialNumber,
610 }}
611 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800612 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700613 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700614 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700615 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700616 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800617 "IntfId": o.PonPortID,
618 "OnuId": o.ID,
619 "VolthaOnuId": msg.OnuID,
620 "OperState": msg.OperState.String(),
621 "AdminState": msg.OperState.String(),
622 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700623 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700624
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700625}
626
Matteo Scandolof9d43412021-01-12 11:11:34 -0800627func (o *Onu) HandleShutdownONU() error {
628
629 dyingGasp := pb.ONUAlarmRequest{
630 AlarmType: "DYING_GASP",
631 SerialNumber: o.Sn(),
632 Status: "on",
633 }
634
635 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
636 onuLogger.WithFields(log.Fields{
637 "OnuId": o.ID,
638 "IntfId": o.PonPortID,
639 "OnuSn": o.Sn(),
640 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
641 return err
642 }
643
644 losReq := pb.ONUAlarmRequest{
645 AlarmType: "ONU_ALARM_LOS",
646 SerialNumber: o.Sn(),
647 Status: "on",
648 }
649
650 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
651 onuLogger.WithFields(log.Fields{
652 "OnuId": o.ID,
653 "IntfId": o.PonPortID,
654 "OnuSn": o.Sn(),
655 }).Errorf("Cannot send LOS: %s", err.Error())
656
657 return err
658 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530659 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800660 // TODO if it's the last ONU on the PON, then send a PON LOS
661
Matteo Scandolocedde462021-03-09 17:37:16 -0800662 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800663 onuLogger.WithFields(log.Fields{
664 "OnuId": o.ID,
665 "IntfId": o.PonPortID,
666 "OnuSn": o.Sn(),
667 }).Errorf("Cannot shutdown ONU: %s", err.Error())
668 return err
669 }
670
671 return nil
672}
673
674func (o *Onu) HandlePowerOnONU() error {
675 intitalState := o.InternalState.Current()
676
677 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800678 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
679 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800680 onuLogger.WithFields(log.Fields{
681 "OnuId": o.ID,
682 "IntfId": o.PonPortID,
683 "OnuSn": o.Sn(),
684 }).Errorf("Cannot poweron ONU: %s", err.Error())
685 return err
686 }
687 }
688
689 // turn off the LOS Alarm
690 losReq := pb.ONUAlarmRequest{
691 AlarmType: "ONU_ALARM_LOS",
692 SerialNumber: o.Sn(),
693 Status: "off",
694 }
695
696 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
697 onuLogger.WithFields(log.Fields{
698 "OnuId": o.ID,
699 "IntfId": o.PonPortID,
700 "OnuSn": o.Sn(),
701 }).Errorf("Cannot send LOS: %s", err.Error())
702 return err
703 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530704 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800705
706 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800707 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800708 onuLogger.WithFields(log.Fields{
709 "OnuId": o.ID,
710 "IntfId": o.PonPortID,
711 "OnuSn": o.Sn(),
712 }).Errorf("Cannot poweron ONU: %s", err.Error())
713 return err
714 }
715
716 // move o directly to enable state only when its a powercycle case
717 // in case of first time o poweron o will be moved to enable on
718 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800719 if intitalState == OnuStateDisabled {
720 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800721 onuLogger.WithFields(log.Fields{
722 "OnuId": o.ID,
723 "IntfId": o.PonPortID,
724 "OnuSn": o.Sn(),
725 }).Errorf("Cannot enable ONU: %s", err.Error())
726 return err
727 }
728 }
729
730 return nil
731}
732
733func (o *Onu) SetAlarm(alarmType string, status string) error {
734 alarmReq := pb.ONUAlarmRequest{
735 AlarmType: alarmType,
736 SerialNumber: o.Sn(),
737 Status: status,
738 }
739
740 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
741 if err != nil {
742 return err
743 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530744 raiseAlarm := false
745 if alarmReq.Status == "on" {
746 raiseAlarm = true
747 }
748 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800749 return nil
750}
751
752func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530753 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700754 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530755 if err != nil {
756 log.Errorf("error in getting msgType %v", err)
757 return
758 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800759 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530760 o.seqNumber = 0
761 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800762 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530763 o.seqNumber++
764 if o.seqNumber > 290 {
765 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
766 }
767 }
768 }
769}
770
Matteo Scandolof9d43412021-01-12 11:11:34 -0800771// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
772// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200773func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800774
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700775 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700776 "omciMsgType": msg.OmciMsg.MessageType,
777 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
778 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700779 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700780 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800781 }).Trace("omci-message-decoded")
782
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000783 if o.OmciMsgCounter < maxOmciMsgCounter {
784 o.OmciMsgCounter++
785 } else {
786 o.OmciMsgCounter = 1
787 }
788 if o.OmciMsgCounter > o.OmciResponseRate {
789 onuLogger.WithFields(log.Fields{
790 "OmciMsgCounter": o.OmciMsgCounter,
791 "OmciResponseRate": o.OmciResponseRate,
792 "omciMsgType": msg.OmciMsg.MessageType,
Matteo Scandoloa96e2242021-09-28 10:13:17 -0700793 "txId": msg.OmciMsg.TransactionID,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200794 }).Debug("skipping-omci-msg-response")
795 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000796 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800797 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800798 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700799 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800800 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800801 onuLogger.WithFields(log.Fields{
802 "IntfId": o.PonPortID,
803 "OnuId": o.ID,
804 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700805 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700806 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800807 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700808
809 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
810 o.PonPort.removeAllocId(o.SerialNumber)
811 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800812 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800813 case omci.MibUploadRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700814 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800815 case omci.MibUploadNextRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700816 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800817 case omci.GetRequestType:
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700818 onuDown := o.AdminLockState == 1
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700819 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId,
820 o.CommittedImageEntityId, o.StandbyImageVersion, o.ActiveImageVersion, o.CommittedImageVersion, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800821 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800822 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700823 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800824 switch msgObj.EntityClass {
825 case me.PhysicalPathTerminationPointEthernetUniClassID:
826 // if we're Setting a PPTP state
Matteo Scandolo8a574812021-05-20 15:18:53 -0700827 // we need to send the appropriate alarm (handled in the UNI struct)
828 uni, err := o.FindUniByEntityId(msgObj.EntityInstance)
829 if err != nil {
830 onuLogger.Error(err)
831 success = false
832 } else {
833 // 1 locks the UNI, 0 unlocks it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800834 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700835 var err error
Himani Chawla13b1ee02021-03-15 01:43:53 +0530836 if adminState == 1 {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700837 err = uni.Disable()
Girish Gowdra996d81e2021-04-21 16:16:27 -0700838 } else {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700839 err = uni.Enable()
Himani Chawla13b1ee02021-03-15 01:43:53 +0530840 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700841 if err != nil {
842 onuLogger.WithFields(log.Fields{
843 "IntfId": o.PonPortID,
844 "OnuId": o.ID,
845 "UniMeId": uni.MeId,
846 "UniId": uni.ID,
847 "SerialNumber": o.Sn(),
848 "Err": err.Error(),
849 }).Warn("cannot-change-uni-status")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800850 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800851 }
Elia Battistonac63b112022-01-12 18:40:49 +0100852 case me.PhysicalPathTerminationPointPotsUniClassID:
853 // if we're Setting a PPTP state
854 // we need to send the appropriate alarm (handled in the POTS struct)
855 pots, err := o.FindPotsByEntityId(msgObj.EntityInstance)
856 if err != nil {
857 onuLogger.Error(err)
858 success = false
859 } else {
860 // 1 locks the UNI, 0 unlocks it
861 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
862 var err error
863 if adminState == 1 {
864 err = pots.Disable()
865 } else {
866 err = pots.Enable()
867 }
868 if err != nil {
869 onuLogger.WithFields(log.Fields{
870 "IntfId": o.PonPortID,
871 "OnuId": o.ID,
872 "PotsMeId": pots.MeId,
873 "PotsId": pots.ID,
874 "SerialNumber": o.Sn(),
875 "Err": err.Error(),
876 }).Warn("cannot-change-pots-status")
877 }
878 }
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700879 case me.OnuGClassID:
880 o.AdminLockState = msgObj.Attributes["AdministrativeState"].(uint8)
881 onuLogger.WithFields(log.Fields{
882 "IntfId": o.PonPortID,
883 "OnuId": o.ID,
884 "SerialNumber": o.Sn(),
885 "AdminLockState": o.AdminLockState,
886 }).Debug("set-onu-admin-lock-state")
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800887 case me.TContClassID:
888 allocId := msgObj.Attributes["AllocId"].(uint16)
889
890 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
891 // otherwise we are adding it
892 if allocId == 255 || allocId == 65535 {
893 onuLogger.WithFields(log.Fields{
894 "IntfId": o.PonPortID,
895 "OnuId": o.ID,
896 "TContId": msgObj.EntityInstance,
897 "AllocId": allocId,
898 "SerialNumber": o.Sn(),
899 }).Trace("freeing-alloc-id-via-omci")
900 o.PonPort.removeAllocId(o.SerialNumber)
901 } else {
902 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
903 onuLogger.WithFields(log.Fields{
904 "IntfId": o.PonPortID,
905 "OnuId": o.ID,
906 "AllocId": allocId,
907 "SerialNumber": o.Sn(),
908 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
909 success = false
910 } else {
911 onuLogger.WithFields(log.Fields{
912 "IntfId": o.PonPortID,
913 "OnuId": o.ID,
914 "TContId": msgObj.EntityInstance,
915 "AllocId": allocId,
916 "SerialNumber": o.Sn(),
917 }).Trace("storing-alloc-id-via-omci")
918 o.PonPort.storeAllocId(allocId, o.SerialNumber)
919 }
920 }
921
922 }
923
924 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700925 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800926 o.MibDataSync++
927 }
928 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700929 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800930 }
931 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800932 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
933 var used bool
934 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700935 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800936 if err == nil {
937 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700938 // GemPort 4069 is reserved for multicast and shared across ONUs
939 if msgObj.EntityInstance != 4069 {
940 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
941 onuLogger.WithFields(log.Fields{
942 "IntfId": o.PonPortID,
943 "OnuId": o.ID,
944 "GemPortId": msgObj.EntityInstance,
945 "SerialNumber": o.Sn(),
946 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
947 } else {
948 onuLogger.WithFields(log.Fields{
949 "IntfId": o.PonPortID,
950 "OnuId": o.ID,
951 "GemPortId": msgObj.EntityInstance,
952 "SerialNumber": o.Sn(),
953 }).Trace("storing-gem-port-id-via-omci")
954 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
955 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800956 }
957 }
958 }
959
960 // if the gemPort is valid then increment the MDS and return a successful response
961 // otherwise fail the request
962 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
963 // validation this check will need to be rewritten
964 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700965 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800966 o.MibDataSync++
967 }
968 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700969 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800970 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800971 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700972 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800973 if err == nil {
974 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
975 onuLogger.WithFields(log.Fields{
976 "IntfId": o.PonPortID,
977 "OnuId": o.ID,
978 "GemPortId": msgObj.EntityInstance,
979 "SerialNumber": o.Sn(),
980 }).Trace("freeing-gem-port-id-via-omci")
981 o.PonPort.removeGemPort(msgObj.EntityInstance)
982 }
983 }
984
Matteo Scandolob5913142021-03-19 16:10:18 -0700985 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800986 o.MibDataSync++
987 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800988 case omci.RebootRequestType:
989
Matteo Scandolob5913142021-03-19 16:10:18 -0700990 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800991
992 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800993 // we run this in a separate goroutine so that
994 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800995 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800996 if err := o.Reboot(10 * time.Second); err != nil {
997 log.WithFields(log.Fields{
998 "IntfId": o.PonPortID,
999 "OnuId": o.ID,
1000 "SerialNumber": o.Sn(),
1001 "err": err,
1002 }).Error("cannot-reboot-onu-after-omci-reboot-request")
1003 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001004 }()
1005 case omci.TestRequestType:
Girish Gowdra161d27a2021-05-05 12:01:44 -07001006 var classID me.ClassID
1007 var omciResult me.Results
1008 var instID uint16
1009 responsePkt, errResp, classID, instID, omciResult = omcilib.CreateTestResponse(msg.OmciPkt, msg.OmciMsg)
1010 // Send TestResult only in case the TestResponse omci result code is me.Success
1011 if responsePkt != nil && errResp == nil && omciResult == me.Success {
1012 if testResultPkt, err := omcilib.CreateTestResult(classID, instID, msg.OmciMsg.TransactionID); err == nil {
1013 // send test results asynchronously
1014 go func() {
1015 // Send test results after a second to emulate async behavior
1016 time.Sleep(1 * time.Second)
1017 if testResultPkt != nil {
1018 if err := o.sendOmciIndication(testResultPkt, msg.OmciMsg.TransactionID, stream); err != nil {
1019 onuLogger.WithFields(log.Fields{
1020 "IntfId": o.PonPortID,
1021 "SerialNumber": o.Sn(),
1022 "omciPacket": testResultPkt,
1023 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1024 "transCorrId": msg.OmciMsg.TransactionID,
1025 }).Errorf("failed-to-send-omci-message: %v", err)
1026 }
1027 }
1028 }()
Matteo Scandolof9d43412021-01-12 11:11:34 -08001029 }
1030 }
Girish Gowdraa539f522021-02-15 23:00:45 -08001031 case omci.SynchronizeTimeRequestType:
1032 // MDS counter increment is not required for this message type
Matteo Scandolob5913142021-03-19 16:10:18 -07001033 responsePkt, _ = omcilib.CreateSyncTimeResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -08001034 case omci.StartSoftwareDownloadRequestType:
1035
1036 o.ImageSoftwareReceivedSections = 0
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301037 o.ImageSectionData = []byte{}
Matteo Scandolob5913142021-03-19 16:10:18 -07001038 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
Matteo Scandolocedde462021-03-09 17:37:16 -08001039
Matteo Scandolob5913142021-03-19 16:10:18 -07001040 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001041 o.MibDataSync++
1042 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
1043 onuLogger.WithFields(log.Fields{
1044 "OnuId": o.ID,
1045 "IntfId": o.PonPortID,
1046 "OnuSn": o.Sn(),
1047 "Err": err.Error(),
1048 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
1049 }
1050 } else {
1051 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001052 "OmciMsgType": msg.OmciMsg.MessageType,
1053 "TransCorrId": msg.OmciMsg.TransactionID,
1054 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001055 "IntfId": o.PonPortID,
1056 "SerialNumber": o.Sn(),
1057 }).Error("error-while-processing-start-software-download-request")
1058 }
1059 case omci.DownloadSectionRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001060 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001061 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001062 "OmciMsgType": msg.OmciMsg.MessageType,
1063 "TransCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001064 "EntityInstance": msgObj.EntityInstance,
1065 "SectionNumber": msgObj.SectionNumber,
1066 "SectionData": msgObj.SectionData,
1067 }).Trace("received-download-section-request")
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001068 //Extracting the first 14 bytes to use as a version for this image.
1069 if o.ImageSoftwareReceivedSections == 0 {
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001070 o.InDownloadImageVersion = string(msgObj.SectionData[0:14])
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001071 }
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301072 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
Matteo Scandolocedde462021-03-09 17:37:16 -08001073 o.ImageSoftwareReceivedSections++
1074 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1075 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1076 onuLogger.WithFields(log.Fields{
1077 "OnuId": o.ID,
1078 "IntfId": o.PonPortID,
1079 "OnuSn": o.Sn(),
1080 "Err": err.Error(),
1081 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1082 }
1083 }
1084 }
1085 case omci.DownloadSectionRequestWithResponseType:
1086 // NOTE we only need to respond if an ACK is requested
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301087 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001088 onuLogger.WithFields(log.Fields{
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301089 "OmciMsgType": msg.OmciMsg.MessageType,
1090 "TransCorrId": msg.OmciMsg.TransactionID,
1091 "EntityInstance": msgObj.EntityInstance,
1092 "SectionNumber": msgObj.SectionNumber,
1093 "SectionData": msgObj.SectionData,
1094 }).Trace("received-download-section-request-with-response-type")
1095 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
1096 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1097
1098 if errResp != nil {
1099 onuLogger.WithFields(log.Fields{
1100 "OmciMsgType": msg.OmciMsg.MessageType,
1101 "TransCorrId": msg.OmciMsg.TransactionID,
1102 "Err": errResp.Error(),
1103 "IntfId": o.PonPortID,
1104 "SerialNumber": o.Sn(),
1105 }).Error("error-while-processing-create-download-section-response")
1106 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
1107 }
1108 o.ImageSoftwareReceivedSections++
Matteo Scandolocedde462021-03-09 17:37:16 -08001109 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001110 case omci.EndSoftwareDownloadRequestType:
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001111 success := o.handleEndSoftwareDownloadRequest(msg)
Matteo Scandolocedde462021-03-09 17:37:16 -08001112
Matteo Scandolocedde462021-03-09 17:37:16 -08001113 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001114 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001115 o.MibDataSync++
1116 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1117 onuLogger.WithFields(log.Fields{
1118 "OnuId": o.ID,
1119 "IntfId": o.PonPortID,
1120 "OnuSn": o.Sn(),
1121 "Err": err.Error(),
1122 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1123 }
1124 } else {
1125 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001126 "OmciMsgType": msg.OmciMsg.MessageType,
1127 "TransCorrId": msg.OmciMsg.TransactionID,
1128 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001129 "IntfId": o.PonPortID,
1130 "SerialNumber": o.Sn(),
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001131 }).Error("error-while-responding-to-end-software-download-request")
Matteo Scandolocedde462021-03-09 17:37:16 -08001132 }
1133 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001134 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001135 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1136 onuLogger.WithFields(log.Fields{
1137 "OnuId": o.ID,
1138 "IntfId": o.PonPortID,
1139 "OnuSn": o.Sn(),
1140 "Err": err.Error(),
1141 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1142 }
1143 }
1144 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001145 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001146 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001147 o.MibDataSync++
1148 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1149 onuLogger.WithFields(log.Fields{
1150 "OnuId": o.ID,
1151 "IntfId": o.PonPortID,
1152 "OnuSn": o.Sn(),
1153 "Err": err.Error(),
1154 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1155 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001156 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001157 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001158 previousActiveImage := o.ActiveImageVersion
1159 o.ActiveImageVersion = o.StandbyImageVersion
1160 o.StandbyImageVersion = previousActiveImage
Matteo Scandolocedde462021-03-09 17:37:16 -08001161 } else {
1162 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1163 }
1164 onuLogger.WithFields(log.Fields{
1165 "OnuId": o.ID,
1166 "IntfId": o.PonPortID,
1167 "OnuSn": o.Sn(),
1168 "ActiveImageEntityId": o.ActiveImageEntityId,
1169 "CommittedImageEntityId": o.CommittedImageEntityId,
1170 }).Info("onu-software-image-activated")
1171
1172 // powercycle the ONU
1173 // we run this in a separate goroutine so that
1174 // the ActivateSoftwareResponse is sent to VOLTHA
1175 // NOTE do we need to wait before rebooting?
1176 go func() {
1177 if err := o.Reboot(10 * time.Second); err != nil {
1178 log.WithFields(log.Fields{
1179 "IntfId": o.PonPortID,
1180 "OnuId": o.ID,
1181 "SerialNumber": o.Sn(),
1182 "err": err,
1183 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1184 }
1185 }()
1186 }
1187 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001188 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001189 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001190 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001191 // TODO validate that the image to commit is:
1192 // - active
1193 // - not already committed
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001194 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandolocedde462021-03-09 17:37:16 -08001195 o.CommittedImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001196 //committed becomes standby
1197 o.StandbyImageVersion = o.CommittedImageVersion
1198 o.CommittedImageVersion = o.ActiveImageVersion
Matteo Scandolocedde462021-03-09 17:37:16 -08001199 } else {
1200 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1201 }
1202 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1203 onuLogger.WithFields(log.Fields{
1204 "OnuId": o.ID,
1205 "IntfId": o.PonPortID,
1206 "OnuSn": o.Sn(),
1207 "Err": err.Error(),
1208 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1209 }
1210 onuLogger.WithFields(log.Fields{
1211 "OnuId": o.ID,
1212 "IntfId": o.PonPortID,
1213 "OnuSn": o.Sn(),
1214 "ActiveImageEntityId": o.ActiveImageEntityId,
1215 "CommittedImageEntityId": o.CommittedImageEntityId,
1216 }).Info("onu-software-image-committed")
1217 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301218 case omci.GetAllAlarmsRequestType:
1219 // Reset the alarm sequence number on receiving get all alarms request.
1220 o.onuAlarmsInfoLock.Lock()
1221 for key, alarmInfo := range o.onuAlarmsInfo {
1222 // reset the alarm sequence no
1223 alarmInfo.SequenceNo = 0
1224 o.onuAlarmsInfo[key] = alarmInfo
1225 }
1226 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001227 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301228 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001229 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301230 responsePkt = nil //Do not send any response for error case
1231 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001232 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001233 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001234 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1235 "omciPkt": msg.OmciPkt,
1236 "omciMsgType": msg.OmciMsg.MessageType,
1237 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001238 "IntfId": o.PonPortID,
1239 "SerialNumber": o.Sn(),
1240 }).Warnf("OMCI-message-not-supported")
1241 }
1242
1243 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001244 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001245 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001246 "IntfId": o.PonPortID,
1247 "SerialNumber": o.Sn(),
1248 "omciPacket": responsePkt,
1249 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1250 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001251 }).Errorf("failed-to-send-omci-message: %v", err)
1252 }
1253 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001254
Pragya Arya324337e2020-02-20 14:35:08 +05301255 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001256 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001257}
Pragya Arya324337e2020-02-20 14:35:08 +05301258
Matteo Scandolof9d43412021-01-12 11:11:34 -08001259// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1260func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1261 indication := &openolt.Indication_OmciInd{
1262 OmciInd: &openolt.OmciIndication{
1263 IntfId: o.PonPortID,
1264 OnuId: o.ID,
1265 Pkt: responsePkt,
1266 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001267 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001268 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1269 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001270 }
1271 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001272 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001273 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001274 "omciPacket": indication.OmciInd.Pkt,
1275 "transCorrId": txId,
1276 }).Trace("omci-message-sent")
1277 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001278}
1279
Matteo Scandolo8a574812021-05-20 15:18:53 -07001280// FindUniById retrieves a UNI by ID
1281func (o *Onu) FindUniById(uniID uint32) (*UniPort, error) {
1282 for _, u := range o.UniPorts {
1283 uni := u.(*UniPort)
1284 if uni.ID == uniID {
1285 return uni, nil
1286 }
Matteo Scandolo27428702019-10-11 16:21:16 -07001287 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001288 return nil, fmt.Errorf("cannot-find-uni-with-id-%d-on-onu-%s", uniID, o.Sn())
1289}
1290
Elia Battistonac63b112022-01-12 18:40:49 +01001291// FindPotsById retrieves a POTS port by ID
1292func (o *Onu) FindPotsById(uniID uint32) (*PotsPort, error) {
1293 for _, p := range o.PotsPorts {
1294 pots := p.(*PotsPort)
1295 if pots.ID == uniID {
1296 return pots, nil
1297 }
1298 }
1299 return nil, fmt.Errorf("cannot-find-pots-with-id-%d-on-onu-%s", uniID, o.Sn())
1300}
1301
Matteo Scandolo8a574812021-05-20 15:18:53 -07001302// FindUniByEntityId retrieves a uni by MeID (the OMCI entity ID)
1303func (o *Onu) FindUniByEntityId(meId uint16) (*UniPort, error) {
1304 entityId := omcilib.EntityID{}.FromUint16(meId)
1305 for _, u := range o.UniPorts {
1306 uni := u.(*UniPort)
1307 if uni.MeId.Equals(entityId) {
1308 return uni, nil
1309 }
1310 }
1311 return nil, fmt.Errorf("cannot-find-uni-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
Matteo Scandolo27428702019-10-11 16:21:16 -07001312}
1313
Elia Battistonac63b112022-01-12 18:40:49 +01001314// FindPotsByEntityId retrieves a POTS uni by MeID (the OMCI entity ID)
1315func (o *Onu) FindPotsByEntityId(meId uint16) (*PotsPort, error) {
1316 entityId := omcilib.EntityID{}.FromUint16(meId)
1317 for _, p := range o.PotsPorts {
1318 pots := p.(*PotsPort)
1319 if pots.MeId.Equals(entityId) {
1320 return pots, nil
1321 }
1322 }
1323 return nil, fmt.Errorf("cannot-find-pots-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
1324}
1325
William Kurkian0418bc82019-11-06 12:16:24 -05001326func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001327 onuLogger.WithFields(log.Fields{
1328 "IntfId": o.PonPortID,
1329 "OnuId": id,
1330 "SerialNumber": o.Sn(),
1331 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001332 o.ID = id
1333}
1334
Matteo Scandolof9d43412021-01-12 11:11:34 -08001335func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001336 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001337 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001338 "Cookie": msg.Flow.Cookie,
1339 "DstPort": msg.Flow.Classifier.DstPort,
1340 "FlowId": msg.Flow.FlowId,
1341 "FlowType": msg.Flow.FlowType,
1342 "GemportId": msg.Flow.GemportId,
1343 "InnerVlan": msg.Flow.Classifier.IVid,
1344 "IntfId": msg.Flow.AccessIntfId,
1345 "IpProto": msg.Flow.Classifier.IpProto,
1346 "OnuId": msg.Flow.OnuId,
1347 "OnuSn": o.Sn(),
1348 "OuterVlan": msg.Flow.Classifier.OVid,
1349 "PortNo": msg.Flow.PortNo,
1350 "SrcPort": msg.Flow.Classifier.SrcPort,
1351 "UniID": msg.Flow.UniId,
1352 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1353 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1354 "ClassifierIVid": msg.Flow.Classifier.IVid,
1355 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001356 "ReplicateFlow": msg.Flow.ReplicateFlow,
1357 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001358 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001359
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001360 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001361
1362 var gemPortId uint32
1363 if msg.Flow.ReplicateFlow {
1364 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1365 // first available gemport (we only need to send one packet)
1366 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1367 gemPortId = msg.Flow.PbitToGemport[0]
1368 } else {
1369 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1370 gemPortId = uint32(msg.Flow.GemportId)
1371 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001372
1373 uni, err := o.FindUniById(uint32(msg.Flow.UniId))
1374 if err != nil {
1375 onuLogger.WithFields(log.Fields{
1376 "IntfId": o.PonPortID,
1377 "OnuId": o.ID,
1378 "UniId": msg.Flow.UniId,
1379 "PortNo": msg.Flow.PortNo,
1380 "SerialNumber": o.Sn(),
1381 "FlowId": msg.Flow.FlowId,
1382 "FlowType": msg.Flow.FlowType,
1383 }).Error("cannot-find-uni-port-for-flow")
1384 }
1385
1386 uni.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
1387 uni.StorePortNo(msg.Flow.PortNo)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001388
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001389 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001390 uni.HandleAuth()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001391 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1392 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001393 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001394 uni.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001395 }
1396}
1397
Matteo Scandolof9d43412021-01-12 11:11:34 -08001398func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001399 onuLogger.WithFields(log.Fields{
1400 "IntfId": o.PonPortID,
1401 "OnuId": o.ID,
1402 "SerialNumber": o.Sn(),
1403 "FlowId": msg.Flow.FlowId,
1404 "FlowType": msg.Flow.FlowType,
1405 }).Debug("ONU receives FlowRemove")
1406
1407 for idx, flow := range o.FlowIds {
1408 // If the gemport is found, delete it from local cache.
1409 if flow == msg.Flow.FlowId {
1410 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1411 break
1412 }
1413 }
1414
1415 if len(o.FlowIds) == 0 {
1416 onuLogger.WithFields(log.Fields{
1417 "IntfId": o.PonPortID,
1418 "OnuId": o.ID,
1419 "SerialNumber": o.Sn(),
1420 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001421
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301422 // check if ONU delete is performed and
1423 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001424 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301425 close(o.Channel)
1426 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001427 }
1428}
1429
Matteo Scandolocedde462021-03-09 17:37:16 -08001430func (o *Onu) Reboot(timeout time.Duration) error {
1431 onuLogger.WithFields(log.Fields{
1432 "IntfId": o.PonPortID,
1433 "OnuId": o.ID,
1434 "SerialNumber": o.Sn(),
1435 }).Debug("shutting-down-onu")
1436 if err := o.HandleShutdownONU(); err != nil {
1437 return err
1438 }
1439 time.Sleep(timeout)
1440 onuLogger.WithFields(log.Fields{
1441 "IntfId": o.PonPortID,
1442 "OnuId": o.ID,
1443 "SerialNumber": o.Sn(),
1444 }).Debug("power-on-onu")
1445 if err := o.HandlePowerOnONU(); err != nil {
1446 return err
1447 }
1448 return nil
1449}
1450
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001451// returns true if the request is successful, false otherwise
1452func (o *Onu) handleEndSoftwareDownloadRequest(msg bbsim.OmciMessage) bool {
1453 msgObj, err := omcilib.ParseEndSoftwareDownloadRequest(msg.OmciPkt)
1454 if err != nil {
1455 onuLogger.WithFields(log.Fields{
1456 "OmciMsgType": msg.OmciMsg.MessageType,
1457 "TransCorrId": msg.OmciMsg.TransactionID,
1458 "Err": err.Error(),
1459 "IntfId": o.PonPortID,
1460 "SerialNumber": o.Sn(),
1461 }).Error("error-while-processing-end-software-download-request")
1462 return false
1463 }
1464
1465 onuLogger.WithFields(log.Fields{
1466 "OnuId": o.ID,
1467 "IntfId": o.PonPortID,
1468 "OnuSn": o.Sn(),
1469 "msgObj": msgObj,
1470 }).Trace("EndSoftwareDownloadRequest received message")
1471
1472 // if the image download is ongoing and we receive a message with
1473 // ImageSize = 0 and Crc = 4294967295 (0xFFFFFFFF) respond with success
1474 if o.ImageSoftwareReceivedSections > 0 &&
1475 msgObj.ImageSize == 0 &&
1476 msgObj.CRC32 == 4294967295 {
1477 o.ImageSoftwareReceivedSections = 0
1478 // NOTE potentially we may want to add a ONU state to reflect
1479 // the software download abort
1480 return true
1481 }
1482
1483 // In the startSoftwareDownload we get the image size and the window size.
1484 // We calculate how many DownloadSection we should receive and validate
1485 // that we got the correct amount when we receive this message
1486 // If the received sections are different from the expected sections
1487 // respond with failure
1488 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1489 onuLogger.WithFields(log.Fields{
1490 "OnuId": o.ID,
1491 "IntfId": o.PonPortID,
1492 "OnuSn": o.Sn(),
1493 "ExpectedSections": o.ImageSoftwareExpectedSections,
1494 "ReceivedSections": o.ImageSoftwareReceivedSections,
1495 }).Errorf("onu-did-not-receive-all-image-sections")
1496 return false
1497 }
1498
1499 // check the received CRC vs the computed CRC
1500 computedCRC := crc32a.Checksum(o.ImageSectionData[:int(msgObj.ImageSize)])
1501 //Convert the crc to network byte order
1502 var byteSlice = make([]byte, 4)
1503 binary.LittleEndian.PutUint32(byteSlice, computedCRC)
1504 computedCRC = binary.BigEndian.Uint32(byteSlice)
1505 if msgObj.CRC32 != computedCRC {
1506 onuLogger.WithFields(log.Fields{
1507 "OnuId": o.ID,
1508 "IntfId": o.PonPortID,
1509 "OnuSn": o.Sn(),
1510 "ReceivedCRC": msgObj.CRC32,
1511 "CalculatedCRC": computedCRC,
1512 }).Errorf("onu-image-crc-validation-failed")
1513 return false
1514 }
1515
1516 o.StandbyImageVersion = o.InDownloadImageVersion
1517 onuLogger.WithFields(log.Fields{
1518 "OnuId": o.ID,
1519 "IntfId": o.PonPortID,
1520 "OnuSn": o.Sn(),
1521 "StandbyVersion": o.StandbyImageVersion,
1522 }).Debug("onu-image-version-updated")
1523 return true
1524}
1525
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001526// BBR methods
1527
1528func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1529 omciMsg := openolt.OmciMsg{
1530 IntfId: intfId,
1531 OnuId: onuId,
1532 Pkt: pktBytes,
1533 }
1534
1535 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1536 log.WithFields(log.Fields{
1537 "IntfId": intfId,
1538 "OnuId": onuId,
1539 "SerialNumber": common.OnuSnToString(sn),
1540 "Pkt": omciMsg.Pkt,
1541 }).Fatalf("Failed to send MIB Reset")
1542 }
1543 log.WithFields(log.Fields{
1544 "IntfId": intfId,
1545 "OnuId": onuId,
1546 "SerialNumber": common.OnuSnToString(sn),
1547 "Pkt": omciMsg.Pkt,
1548 }).Tracef("Sent OMCI message %s", msgType)
1549}
1550
1551func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1552 var next uint16
1553 if len(highPriority) > 0 && highPriority[0] {
1554 next = onu.hpTid
1555 onu.hpTid += 1
1556 if onu.hpTid < 0x8000 {
1557 onu.hpTid = 0x8000
1558 }
1559 } else {
1560 next = onu.tid
1561 onu.tid += 1
1562 if onu.tid >= 0x8000 {
1563 onu.tid = 1
1564 }
1565 }
1566 return next
1567}
1568
1569// TODO move this method in responders/omcisim
Matteo Scandolo8a574812021-05-20 15:18:53 -07001570// StartOmci is called in BBR to start the OMCI state machine
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001571func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1572 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1573 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1574}
1575
Matteo Scandolof9d43412021-01-12 11:11:34 -08001576// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1577func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1578
1579 // we need to encode the packet in HEX
1580 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1581 hex.Encode(pkt, msg.OmciInd.Pkt)
1582 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1583 if err != nil {
1584 log.WithFields(log.Fields{
1585 "IntfId": o.PonPortID,
1586 "SerialNumber": o.Sn(),
1587 "omciPacket": msg.OmciInd.Pkt,
1588 }).Error("BBR Cannot parse OMCI packet")
1589 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001590
1591 log.WithFields(log.Fields{
1592 "IntfId": msg.OmciInd.IntfId,
1593 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001594 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001595 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001596 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301597 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001598 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001599 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001600 log.WithFields(log.Fields{
1601 "IntfId": msg.OmciInd.IntfId,
1602 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001603 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001604 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001605 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001606 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001607 case omci.MibResetResponseType:
1608 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1609 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1610 case omci.MibUploadResponseType:
1611 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1612 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1613 case omci.MibUploadNextResponseType:
1614 o.seqNumber++
Matteo Scandolo8a574812021-05-20 15:18:53 -07001615 // once the mibUpload is complete send a SetRequest for the PPTP to enable the UNI
1616 // NOTE that in BBR we only enable the first UNI
1617 if o.seqNumber == o.MibDb.NumberOfCommands {
1618 meId := omcilib.GenerateUniPortEntityId(1)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001619
Matteo Scandolo8a574812021-05-20 15:18:53 -07001620 meParams := me.ParamData{
1621 EntityID: meId.ToUint16(),
1622 Attributes: me.AttributeValueMap{"AdministrativeState": 0},
1623 }
1624 managedEntity, omciError := me.NewPhysicalPathTerminationPointEthernetUni(meParams)
1625 if omciError.GetError() != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001626 onuLogger.WithFields(log.Fields{
1627 "OnuId": o.ID,
1628 "IntfId": o.PonPortID,
1629 "OnuSn": o.Sn(),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001630 }).Fatal(omciError.GetError())
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001631 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001632
1633 setPPtp, _ := omcilib.CreateSetRequest(managedEntity, 1)
1634 sendOmciMsg(setPPtp, o.PonPortID, o.ID, o.SerialNumber, "setRquest", client)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001635 } else {
1636 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1637 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001638 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001639 case omci.SetResponseType:
1640 // once we set the PPTP to active we can start sending flows
1641
1642 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
1643 onuLogger.WithFields(log.Fields{
1644 "OnuId": o.ID,
1645 "IntfId": o.PonPortID,
1646 "OnuSn": o.Sn(),
1647 }).Errorf("Error while transitioning ONU State %v", err)
1648 }
1649 case omci.AlarmNotificationType:
1650 log.Info("bbr-received-alarm")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001651 }
1652}
1653
1654func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1655
1656 classifierProto := openolt.Classifier{
1657 EthType: uint32(layers.EthernetTypeEAPOL),
1658 OVid: 4091,
1659 }
1660
1661 actionProto := openolt.Action{}
1662
1663 downstreamFlow := openolt.Flow{
1664 AccessIntfId: int32(o.PonPortID),
1665 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001666 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001667 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001668 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001669 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001670 Classifier: &classifierProto,
1671 Action: &actionProto,
1672 Priority: int32(100),
1673 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001674 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1675 // AllocId and GemPorts need to be unique per PON
1676 // for now use the ONU-ID, will need to change once we support multiple UNIs
1677 AllocId: int32(o.ID),
1678 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001679 }
1680
1681 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1682 log.WithFields(log.Fields{
1683 "IntfId": o.PonPortID,
1684 "OnuId": o.ID,
1685 "FlowId": downstreamFlow.FlowId,
1686 "PortNo": downstreamFlow.PortNo,
1687 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001688 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001689 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001690 }
1691 log.WithFields(log.Fields{
1692 "IntfId": o.PonPortID,
1693 "OnuId": o.ID,
1694 "FlowId": downstreamFlow.FlowId,
1695 "PortNo": downstreamFlow.PortNo,
1696 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1697 }).Info("Sent EAPOL Flow")
1698}
1699
1700func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001701
Matteo Scandolo8a574812021-05-20 15:18:53 -07001702 // BBR only works with a single UNI and a single service (ATT HSIA)
1703 hsia := o.UniPorts[0].(*UniPort).Services[0].(*Service)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001704 classifierProto := openolt.Classifier{
1705 EthType: uint32(layers.EthernetTypeIPv4),
1706 SrcPort: uint32(68),
1707 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001708 OVid: uint32(hsia.CTag),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001709 OPbits: 255,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001710 }
1711
1712 actionProto := openolt.Action{}
1713
1714 downstreamFlow := openolt.Flow{
1715 AccessIntfId: int32(o.PonPortID),
1716 OnuId: int32(o.ID),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001717 UniId: int32(0), // BBR only supports a single UNI
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001718 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001719 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001720 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001721 Classifier: &classifierProto,
1722 Action: &actionProto,
1723 Priority: int32(100),
1724 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001725 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1726 // AllocId and GemPorts need to be unique per PON
1727 // for now use the ONU-ID, will need to change once we support multiple UNIs
1728 AllocId: int32(o.ID),
1729 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001730 }
1731
1732 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1733 log.WithFields(log.Fields{
1734 "IntfId": o.PonPortID,
1735 "OnuId": o.ID,
1736 "FlowId": downstreamFlow.FlowId,
1737 "PortNo": downstreamFlow.PortNo,
1738 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001739 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001740 }).Fatalf("Failed to send DHCP Flow")
1741 }
1742 log.WithFields(log.Fields{
1743 "IntfId": o.PonPortID,
1744 "OnuId": o.ID,
1745 "FlowId": downstreamFlow.FlowId,
1746 "PortNo": downstreamFlow.PortNo,
1747 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1748 }).Info("Sent DHCP Flow")
1749}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301750
1751// DeleteFlow method search and delete flowKey from the onu flows slice
1752func (onu *Onu) DeleteFlow(key FlowKey) {
1753 for pos, flowKey := range onu.Flows {
1754 if flowKey == key {
1755 // delete the flowKey by shifting all flowKeys by one
1756 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1757 t := make([]FlowKey, len(onu.Flows))
1758 copy(t, onu.Flows)
1759 onu.Flows = t
1760 break
1761 }
1762 }
1763}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301764
1765func (onu *Onu) ReDiscoverOnu() {
1766 // Wait for few seconds to be sure of the cleanup
1767 time.Sleep(5 * time.Second)
1768
1769 onuLogger.WithFields(log.Fields{
1770 "IntfId": onu.PonPortID,
1771 "OnuId": onu.ID,
1772 "OnuSn": onu.Sn(),
1773 }).Debug("Send ONU Re-Discovery")
1774
1775 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001776 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301777 log.WithFields(log.Fields{
1778 "IntfId": onu.PonPortID,
1779 "OnuSn": onu.Sn(),
1780 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001781 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301782 }
1783
Matteo Scandolocedde462021-03-09 17:37:16 -08001784 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301785 log.WithFields(log.Fields{
1786 "IntfId": onu.PonPortID,
1787 "OnuSn": onu.Sn(),
1788 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001789 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301790 }
1791}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001792
Matteo Scandolo8a574812021-05-20 15:18:53 -07001793// deprecated, delegate this to the uniPort
Matteo Scandolo4a036262020-08-17 15:56:13 -07001794func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001795 // FIXME is there a better way to avoid this loop?
1796 for _, u := range onu.UniPorts {
1797 uni := u.(*UniPort)
1798 for _, s := range uni.Services {
1799 service := s.(*Service)
1800 if service.HwAddress.String() == macAddress.String() {
1801 return service, nil
1802 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001803 }
1804 }
1805 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1806}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301807
Matteo Scandolo8a574812021-05-20 15:18:53 -07001808func (onu *Onu) findUniByPortNo(portNo uint32) (*UniPort, error) {
1809 for _, u := range onu.UniPorts {
1810 uni := u.(*UniPort)
1811 if uni.PortNo == portNo {
1812 return uni, nil
1813 }
1814 }
1815 return nil, fmt.Errorf("cannot-find-uni-with-port-no-%d", portNo)
1816}
1817
Himani Chawla13b1ee02021-03-15 01:43:53 +05301818func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1819 switch alarmType {
1820 case "ONU_ALARM_LOS":
1821 msg := bbsim.Message{
1822 Type: bbsim.UniStatusAlarm,
1823 Data: bbsim.UniStatusAlarmMessage{
1824 OnuSN: o.SerialNumber,
1825 OnuID: o.ID,
1826 EntityID: 257,
1827 RaiseOMCIAlarm: raiseOMCIAlarm,
1828 },
1829 }
1830 o.Channel <- msg
1831 }
1832
1833}
1834
1835func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1836 o.onuAlarmsInfoLock.Lock()
1837 defer o.onuAlarmsInfoLock.Unlock()
1838 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1839 if alarmInfo.SequenceNo == 255 {
1840 alarmInfo.SequenceNo = 1
1841 } else {
1842 alarmInfo.SequenceNo++
1843 }
1844 o.onuAlarmsInfo[key] = alarmInfo
1845 return alarmInfo.SequenceNo
1846 } else {
1847 // This is the first time alarm notification message is being sent
1848 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1849 SequenceNo: 1,
1850 }
1851 return 1
1852 }
1853}
Elia Battistonfe017662022-01-05 11:43:16 +01001854
1855func (o *Onu) InvalidateMibDataSync() {
1856 rand.Seed(time.Now().UnixNano())
1857 r := uint8(rand.Intn(10) + 1)
1858
1859 o.MibDataSync += r
1860
1861 // Since MibDataSync is a uint8, summing to it will never
1862 // result in a value higher than 255, but could be 0
1863 if o.MibDataSync == 0 {
1864 o.MibDataSync++
1865 }
1866}