blob: 53f6564e64f66ee2a383dcd0a4e28e156e5b89f2 [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
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070096type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -080097 ID uint32
98 PonPortID uint32
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070099 PonPort *PonPort
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800100 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +0530101 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
102 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandolo4a036262020-08-17 15:56:13 -0700103
Matteo Scandolo4a036262020-08-17 15:56:13 -0700104 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800105 // ONU State
Elia Battistonac63b112022-01-12 18:40:49 +0100106 UniPorts []UniPortIf
107 PotsPorts []PotsPortIf
Elia Battistonac63b112022-01-12 18:40:49 +0100108 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700109
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700110 OperState *fsm.FSM
111 SerialNumber *openolt.SerialNumber
112
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700113 AdminLockState uint8 // 0 is enabled, 1 is disabled.
114
Matteo Scandolof9d43412021-01-12 11:11:34 -0800115 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700116
117 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800118 MibDataSync uint8
119 ImageSoftwareExpectedSections int
120 ImageSoftwareReceivedSections int
121 ActiveImageEntityId uint16
122 CommittedImageEntityId uint16
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700123 StandbyImageVersion string
124 ActiveImageVersion string
Matteo Scandolo76f6b892021-11-15 16:13:06 -0800125 InDownloadImageVersion string
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700126 CommittedImageVersion string
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000127 OmciResponseRate uint8
128 OmciMsgCounter uint8
Himani Chawla4ff5fab2021-11-09 19:19:29 +0530129 ImageSectionData []byte
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800130
131 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700132 tid uint16
133 hpTid uint16
134 seqNumber uint16
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700135 MibDb *omcilib.MibDb
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700136
Anand S Katti09541352020-01-29 15:54:01 +0530137 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
138 TrafficSchedulers *tech_profile.TrafficSchedulers
Himani Chawla13b1ee02021-03-15 01:43:53 +0530139 onuAlarmsInfoLock sync.RWMutex
140 onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700141}
142
Matteo Scandolo99f18462019-10-28 14:14:28 -0700143func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700144 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700145}
146
Matteo Scandolo8a574812021-05-20 15:18:53 -0700147func 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 -0700148
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700149 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800150 ID: id,
151 PonPortID: pon.ID,
152 PonPort: pon,
Matteo Scandolocedde462021-03-09 17:37:16 -0800153 tid: 0x1,
154 hpTid: 0x8000,
155 seqNumber: 0,
156 DoneChannel: make(chan bool, 1),
157 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
yasin saplid4445982022-01-25 09:30:30 +0000158 FlowIds: []uint64{},
Matteo Scandolocedde462021-03-09 17:37:16 -0800159 DiscoveryDelay: delay,
160 MibDataSync: 0,
161 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
162 ImageSoftwareReceivedSections: 0,
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700163 //TODO this needs reworking, it's always 0 or 1, possibly base all on the version
164 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
165 CommittedImageEntityId: 0,
166 StandbyImageVersion: "BBSM_IMG_00000",
167 ActiveImageVersion: "BBSM_IMG_00001",
168 CommittedImageVersion: "BBSM_IMG_00001",
169 OmciResponseRate: olt.OmciResponseRate,
170 OmciMsgCounter: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700171 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800172 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700173 // NOTE this state machine is used to track the operational
174 // state as requested by VOLTHA
175 o.OperState = getOperStateFSM(func(e *fsm.Event) {
176 onuLogger.WithFields(log.Fields{
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700177 "OnuId": o.ID,
178 "IntfId": o.PonPortID,
179 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700180 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
181 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530182 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700183 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
184 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800185 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700186 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700187 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800188 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
189 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
190 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100191 // 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 -0800192 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530193 // 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 +0200194 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted, OnuStateImageDownloadComplete}, Dst: OnuStatePonDisabled},
Matteo Scandolocedde462021-03-09 17:37:16 -0800195 // Software Image Download related states
Matteo Scandolo9f4bf4f2021-06-22 09:41:02 +0200196 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateImageDownloadStarted},
Matteo Scandolocedde462021-03-09 17:37:16 -0800197 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
198 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
199 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
200 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
201 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700202 // BBR States
203 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800204 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
205 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700206 },
207 fsm.Callbacks{
208 "enter_state": func(e *fsm.Event) {
209 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700210 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700211 fmt.Sprintf("enter_%s", OnuStateInitialized): func(e *fsm.Event) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100212 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800213 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800214
Matteo Scandolocedde462021-03-09 17:37:16 -0800215 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800216 onuLogger.WithFields(log.Fields{
217 "OnuId": o.ID,
218 "IntfId": o.PonPortID,
219 "OnuSn": o.Sn(),
220 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
221 }
222
Pragya Arya1cbefa42020-01-13 12:15:29 +0530223 if !isMock {
224 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700225 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530226 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100227 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700228 fmt.Sprintf("enter_%s", OnuStateDiscovered): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800229 msg := bbsim.Message{
230 Type: bbsim.OnuDiscIndication,
231 Data: bbsim.OnuDiscIndicationMessage{
232 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100233 },
234 }
235 o.Channel <- msg
236 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700237 fmt.Sprintf("enter_%s", OnuStateEnabled): func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800238
239 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
240 onuLogger.WithFields(log.Fields{
241 "IntfId": o.PonPortID,
242 "OnuId": o.ID,
243 "SerialNumber": o.Sn(),
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700244 }).Errorf("onu-id-duplicated-with-%s", common.OnuSnToString(sn))
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800245 return
246 } else {
247 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
248 }
249
Matteo Scandolof9d43412021-01-12 11:11:34 -0800250 msg := bbsim.Message{
251 Type: bbsim.OnuIndication,
252 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700253 OnuSN: o.SerialNumber,
254 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800255 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700256 },
257 }
258 o.Channel <- msg
259 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700260 fmt.Sprintf("enter_%s", OnuStateDisabled): func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700261
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700262 o.cleanupOnuState()
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700263
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700264 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800265 if err := o.OperState.Event("disable"); err != nil {
266 onuLogger.WithFields(log.Fields{
267 "OnuId": o.ID,
268 "IntfId": o.PonPortID,
269 "OnuSn": o.Sn(),
270 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
271 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700272 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800273 msg := bbsim.Message{
274 Type: bbsim.OnuIndication,
275 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700276 OnuSN: o.SerialNumber,
277 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800278 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700279 },
280 }
281 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530282
Matteo Scandolo8a574812021-05-20 15:18:53 -0700283 // disable the UNI ports
284 for _, uni := range o.UniPorts {
285 _ = uni.Disable()
286 }
287
Elia Battistonac63b112022-01-12 18:40:49 +0100288 // disable the POTS UNI ports
289 for _, pots := range o.PotsPorts {
290 _ = pots.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{
Elia Battistonac63b112022-01-12 18:40:49 +0100319 "OnuId": o.ID,
320 "IntfId": o.PonPortID,
321 "OnuSn": o.Sn(),
322 "NumUni": olt.NumUni,
323 "NumPots": olt.NumPots,
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700324 }).Debug("creating-uni-ports")
Elia Battistonac63b112022-01-12 18:40:49 +0100325
326 // create Ethernet UNIs
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700327 for i := 0; i < olt.NumUni; i++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700328 uni, err := NewUniPort(uint32(i), &o, nextCtag, nextStag)
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700329 if err != nil {
330 onuLogger.WithFields(log.Fields{
331 "OnuId": o.ID,
332 "IntfId": o.PonPortID,
333 "OnuSn": o.Sn(),
334 "Err": err,
335 }).Fatal("cannot-create-uni-port")
336 }
337 o.UniPorts = append(o.UniPorts, uni)
338 }
Elia Battistonac63b112022-01-12 18:40:49 +0100339 // create POTS UNIs, with progressive IDs
340 for i := olt.NumUni; i < (olt.NumUni + olt.NumPots); i++ {
341 pots, err := NewPotsPort(uint32(i), &o)
342 if err != nil {
343 onuLogger.WithFields(log.Fields{
344 "OnuId": o.ID,
345 "IntfId": o.PonPortID,
346 "OnuSn": o.Sn(),
347 "Err": err,
348 }).Fatal("cannot-create-pots-port")
349 }
350 o.PotsPorts = append(o.PotsPorts, pots)
351 }
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700352
Elia Battistonac63b112022-01-12 18:40:49 +0100353 mibDb, err := omcilib.GenerateMibDatabase(len(o.UniPorts), len(o.PotsPorts))
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700354 if err != nil {
355 onuLogger.WithFields(log.Fields{
356 "OnuId": o.ID,
357 "IntfId": o.PonPortID,
358 "OnuSn": o.Sn(),
359 }).Fatal("cannot-generate-mibdb-for-onu")
360 }
361 o.MibDb = mibDb
362
Matteo Scandolo27428702019-10-11 16:21:16 -0700363 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700364}
365
William Kurkian0418bc82019-11-06 12:16:24 -0500366func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700367 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700368 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700369 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700370 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700371 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
372}
373
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700374// cleanupOnuState this method is to clean the local state when the ONU is disabled
375func (o *Onu) cleanupOnuState() {
376 // clean the ONU state
yasin saplid4445982022-01-25 09:30:30 +0000377 o.FlowIds = []uint64{}
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700378 o.PonPort.removeOnuId(o.ID)
379 o.PonPort.removeAllocId(o.SerialNumber)
380 o.PonPort.removeGemPortBySn(o.SerialNumber)
381
382 o.onuAlarmsInfoLock.Lock()
383 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
384 o.onuAlarmsInfoLock.Unlock()
385}
386
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100387// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000388func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700389 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100390 "onuID": o.ID,
391 "onuSN": o.Sn(),
392 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700393 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100394 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700395
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700396 defer onuLogger.WithFields(log.Fields{
397 "onuID": o.ID,
398 "onuSN": o.Sn(),
399 "stream": stream,
400 }).Debug("Stopped handling ONU Indication Channel")
401
David Bainbridge103cf022019-12-16 20:11:35 +0000402loop:
403 for {
404 select {
405 case <-ctx.Done():
406 onuLogger.WithFields(log.Fields{
407 "onuID": o.ID,
408 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700409 }).Debug("ONU message handling canceled via context")
410 break loop
411 case <-stream.Context().Done():
412 onuLogger.WithFields(log.Fields{
413 "onuID": o.ID,
414 "onuSN": o.Sn(),
415 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000416 break loop
417 case message, ok := <-o.Channel:
418 if !ok || ctx.Err() != nil {
419 onuLogger.WithFields(log.Fields{
420 "onuID": o.ID,
421 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700422 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000423 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700424 }
David Bainbridge103cf022019-12-16 20:11:35 +0000425 onuLogger.WithFields(log.Fields{
426 "onuID": o.ID,
427 "onuSN": o.Sn(),
428 "messageType": message.Type,
429 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700430
David Bainbridge103cf022019-12-16 20:11:35 +0000431 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800432 case bbsim.OnuDiscIndication:
433 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000434 // 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 +0530435 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000436 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800437 case bbsim.OnuIndication:
438 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000439 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800440 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800441 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800442 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200443 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800444 case bbsim.UniStatusAlarm:
445 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530446 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
447 MeInstance: msg.EntityID,
448 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
449 }
450 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
451 o.onuAlarmsInfoLock.Lock()
452 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
453 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
454 if pkt != nil { //pkt will be nil if we are unable to create the alarm
455 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
456 onuLogger.WithFields(log.Fields{
457 "IntfId": o.PonPortID,
458 "SerialNumber": o.Sn(),
459 "omciPacket": pkt,
460 "adminState": msg.AdminState,
461 "entityID": msg.EntityID,
462 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
463 alarmInfo.SequenceNo--
464 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800465 onuLogger.WithFields(log.Fields{
466 "IntfId": o.PonPortID,
467 "SerialNumber": o.Sn(),
468 "omciPacket": pkt,
469 "adminState": msg.AdminState,
470 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530471 }).Trace("UNI-Link-alarm-sent")
472 if alarmBitMap == [28]byte{0} {
473 delete(o.onuAlarmsInfo, onuAlarmMapKey)
474 } else {
475 alarmInfo.AlarmBitMap = alarmBitMap
476 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
477 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800478 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530479 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800480 case bbsim.FlowAdd:
481 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700482 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800483 case bbsim.FlowRemoved:
484 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700485 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800486 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700487
Matteo Scandolof9d43412021-01-12 11:11:34 -0800488 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000489
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700490 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000491 "IntfId": msg.IntfId,
492 "OnuId": msg.OnuId,
493 "pktType": msg.Type,
494 }).Trace("Received OnuPacketOut Message")
495
Matteo Scandolo8a574812021-05-20 15:18:53 -0700496 uni, err := o.findUniByPortNo(msg.PortNo)
Matteo Scandolo618a6582020-09-09 12:21:29 -0700497
Matteo Scandolo8a574812021-05-20 15:18:53 -0700498 if err != nil {
499 onuLogger.WithFields(log.Fields{
500 "IntfId": msg.IntfId,
501 "OnuId": msg.OnuId,
502 "pktType": msg.Type,
503 "portNo": msg.PortNo,
504 "MacAddress": msg.MacAddress,
505 "Pkt": hex.EncodeToString(msg.Packet.Data()),
506 "OnuSn": o.Sn(),
507 }).Error("Cannot find Uni associated with packet")
508 return
David Bainbridge103cf022019-12-16 20:11:35 +0000509 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700510 uni.PacketCh <- msg
511 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800512 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000513 // NOTE we only receive BBR packets here.
514 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
515 // 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 -0800516 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000517
Matteo Scandolo8a574812021-05-20 15:18:53 -0700518 onuLogger.WithFields(log.Fields{
519 "IntfId": msg.IntfId,
520 "OnuId": msg.OnuId,
521 "PortNo": msg.PortNo,
522 "GemPortId": msg.GemPortId,
523 "pktType": msg.Type,
David Bainbridge103cf022019-12-16 20:11:35 +0000524 }).Trace("Received OnuPacketIn Message")
525
Matteo Scandolo8a574812021-05-20 15:18:53 -0700526 uni, err := o.findUniByPortNo(msg.PortNo)
527 if err != nil {
528 onuLogger.WithFields(log.Fields{
529 "IntfId": msg.IntfId,
530 "OnuId": msg.OnuId,
531 "PortNo": msg.PortNo,
532 "GemPortId": msg.GemPortId,
533 "pktType": msg.Type,
534 }).Error(err.Error())
535 }
536
537 // BBR has one service and one UNI
538 serviceId := uint32(0)
539 oltId := 0
David Bainbridge103cf022019-12-16 20:11:35 +0000540 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700541 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 +0000542 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700543 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000544 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800545 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800546 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800547 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
548 o.handleOmciResponse(msg, client)
549 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000550 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800551 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000552 o.sendDhcpFlow(client)
553 default:
554 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700555 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700556 }
557 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700558}
559
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800560func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700561 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700562 sn.VendorId = []byte("BBSM")
563 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700564 return sn
565}
566
Matteo Scandolof9d43412021-01-12 11:11:34 -0800567func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700568 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800569 IntfId: o.PonPortID,
570 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700571 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700572
Matteo Scandolo4747d292019-08-05 11:50:18 -0700573 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700574 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700575 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700576 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700577
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700578 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800579 "IntfId": o.PonPortID,
580 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700581 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700582 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800583 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800584
585 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
586 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800587 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800588 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800589 o.sendOnuDiscIndication(msg, stream)
590 }
591 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700592}
593
Matteo Scandolof9d43412021-01-12 11:11:34 -0800594func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800595 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
596 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700597
598 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700599 IntfId: o.PonPortID,
600 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700601 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700602 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700603 SerialNumber: o.SerialNumber,
604 }}
605 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800606 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700607 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700608 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700609 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700610 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800611 "IntfId": o.PonPortID,
612 "OnuId": o.ID,
613 "VolthaOnuId": msg.OnuID,
614 "OperState": msg.OperState.String(),
615 "AdminState": msg.OperState.String(),
616 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700617 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700618
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700619}
620
Matteo Scandolof9d43412021-01-12 11:11:34 -0800621func (o *Onu) HandleShutdownONU() error {
622
623 dyingGasp := pb.ONUAlarmRequest{
624 AlarmType: "DYING_GASP",
625 SerialNumber: o.Sn(),
626 Status: "on",
627 }
628
629 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
630 onuLogger.WithFields(log.Fields{
631 "OnuId": o.ID,
632 "IntfId": o.PonPortID,
633 "OnuSn": o.Sn(),
634 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
635 return err
636 }
637
638 losReq := pb.ONUAlarmRequest{
639 AlarmType: "ONU_ALARM_LOS",
640 SerialNumber: o.Sn(),
641 Status: "on",
642 }
643
644 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
645 onuLogger.WithFields(log.Fields{
646 "OnuId": o.ID,
647 "IntfId": o.PonPortID,
648 "OnuSn": o.Sn(),
649 }).Errorf("Cannot send LOS: %s", err.Error())
650
651 return err
652 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530653 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800654 // TODO if it's the last ONU on the PON, then send a PON LOS
655
Matteo Scandolocedde462021-03-09 17:37:16 -0800656 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800657 onuLogger.WithFields(log.Fields{
658 "OnuId": o.ID,
659 "IntfId": o.PonPortID,
660 "OnuSn": o.Sn(),
661 }).Errorf("Cannot shutdown ONU: %s", err.Error())
662 return err
663 }
664
665 return nil
666}
667
668func (o *Onu) HandlePowerOnONU() error {
669 intitalState := o.InternalState.Current()
670
671 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800672 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
673 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800674 onuLogger.WithFields(log.Fields{
675 "OnuId": o.ID,
676 "IntfId": o.PonPortID,
677 "OnuSn": o.Sn(),
678 }).Errorf("Cannot poweron ONU: %s", err.Error())
679 return err
680 }
681 }
682
683 // turn off the LOS Alarm
684 losReq := pb.ONUAlarmRequest{
685 AlarmType: "ONU_ALARM_LOS",
686 SerialNumber: o.Sn(),
687 Status: "off",
688 }
689
690 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
691 onuLogger.WithFields(log.Fields{
692 "OnuId": o.ID,
693 "IntfId": o.PonPortID,
694 "OnuSn": o.Sn(),
695 }).Errorf("Cannot send LOS: %s", err.Error())
696 return err
697 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530698 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800699
700 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800701 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800702 onuLogger.WithFields(log.Fields{
703 "OnuId": o.ID,
704 "IntfId": o.PonPortID,
705 "OnuSn": o.Sn(),
706 }).Errorf("Cannot poweron ONU: %s", err.Error())
707 return err
708 }
709
710 // move o directly to enable state only when its a powercycle case
711 // in case of first time o poweron o will be moved to enable on
712 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800713 if intitalState == OnuStateDisabled {
714 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800715 onuLogger.WithFields(log.Fields{
716 "OnuId": o.ID,
717 "IntfId": o.PonPortID,
718 "OnuSn": o.Sn(),
719 }).Errorf("Cannot enable ONU: %s", err.Error())
720 return err
721 }
722 }
723
724 return nil
725}
726
727func (o *Onu) SetAlarm(alarmType string, status string) error {
728 alarmReq := pb.ONUAlarmRequest{
729 AlarmType: alarmType,
730 SerialNumber: o.Sn(),
731 Status: status,
732 }
733
734 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
735 if err != nil {
736 return err
737 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530738 raiseAlarm := false
739 if alarmReq.Status == "on" {
740 raiseAlarm = true
741 }
742 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800743 return nil
744}
745
746func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530747 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700748 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530749 if err != nil {
750 log.Errorf("error in getting msgType %v", err)
751 return
752 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800753 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530754 o.seqNumber = 0
755 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800756 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530757 o.seqNumber++
758 if o.seqNumber > 290 {
759 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
760 }
761 }
762 }
763}
764
Matteo Scandolof9d43412021-01-12 11:11:34 -0800765// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
766// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200767func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800768
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700769 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700770 "omciMsgType": msg.OmciMsg.MessageType,
771 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
772 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700773 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700774 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800775 }).Trace("omci-message-decoded")
776
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000777 if o.OmciMsgCounter < maxOmciMsgCounter {
778 o.OmciMsgCounter++
779 } else {
780 o.OmciMsgCounter = 1
781 }
782 if o.OmciMsgCounter > o.OmciResponseRate {
783 onuLogger.WithFields(log.Fields{
784 "OmciMsgCounter": o.OmciMsgCounter,
785 "OmciResponseRate": o.OmciResponseRate,
786 "omciMsgType": msg.OmciMsg.MessageType,
Matteo Scandoloa96e2242021-09-28 10:13:17 -0700787 "txId": msg.OmciMsg.TransactionID,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200788 }).Debug("skipping-omci-msg-response")
789 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000790 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800791 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800792 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700793 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800794 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800795 onuLogger.WithFields(log.Fields{
796 "IntfId": o.PonPortID,
797 "OnuId": o.ID,
798 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700799 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700800 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800801 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700802
803 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
804 o.PonPort.removeAllocId(o.SerialNumber)
805 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800806 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800807 case omci.MibUploadRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700808 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800809 case omci.MibUploadNextRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700810 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800811 case omci.GetRequestType:
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700812 onuDown := o.AdminLockState == 1
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700813 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId,
814 o.CommittedImageEntityId, o.StandbyImageVersion, o.ActiveImageVersion, o.CommittedImageVersion, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800815 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800816 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700817 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800818 switch msgObj.EntityClass {
819 case me.PhysicalPathTerminationPointEthernetUniClassID:
820 // if we're Setting a PPTP state
Matteo Scandolo8a574812021-05-20 15:18:53 -0700821 // we need to send the appropriate alarm (handled in the UNI struct)
822 uni, err := o.FindUniByEntityId(msgObj.EntityInstance)
823 if err != nil {
824 onuLogger.Error(err)
825 success = false
826 } else {
827 // 1 locks the UNI, 0 unlocks it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800828 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700829 var err error
Himani Chawla13b1ee02021-03-15 01:43:53 +0530830 if adminState == 1 {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700831 err = uni.Disable()
Girish Gowdra996d81e2021-04-21 16:16:27 -0700832 } else {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700833 err = uni.Enable()
Himani Chawla13b1ee02021-03-15 01:43:53 +0530834 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700835 if err != nil {
836 onuLogger.WithFields(log.Fields{
837 "IntfId": o.PonPortID,
838 "OnuId": o.ID,
839 "UniMeId": uni.MeId,
840 "UniId": uni.ID,
841 "SerialNumber": o.Sn(),
842 "Err": err.Error(),
843 }).Warn("cannot-change-uni-status")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800844 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800845 }
Elia Battistonac63b112022-01-12 18:40:49 +0100846 case me.PhysicalPathTerminationPointPotsUniClassID:
847 // if we're Setting a PPTP state
848 // we need to send the appropriate alarm (handled in the POTS struct)
849 pots, err := o.FindPotsByEntityId(msgObj.EntityInstance)
850 if err != nil {
851 onuLogger.Error(err)
852 success = false
853 } else {
854 // 1 locks the UNI, 0 unlocks it
855 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
856 var err error
857 if adminState == 1 {
858 err = pots.Disable()
859 } else {
860 err = pots.Enable()
861 }
862 if err != nil {
863 onuLogger.WithFields(log.Fields{
864 "IntfId": o.PonPortID,
865 "OnuId": o.ID,
866 "PotsMeId": pots.MeId,
867 "PotsId": pots.ID,
868 "SerialNumber": o.Sn(),
869 "Err": err.Error(),
870 }).Warn("cannot-change-pots-status")
871 }
872 }
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700873 case me.OnuGClassID:
874 o.AdminLockState = msgObj.Attributes["AdministrativeState"].(uint8)
875 onuLogger.WithFields(log.Fields{
876 "IntfId": o.PonPortID,
877 "OnuId": o.ID,
878 "SerialNumber": o.Sn(),
879 "AdminLockState": o.AdminLockState,
880 }).Debug("set-onu-admin-lock-state")
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800881 case me.TContClassID:
882 allocId := msgObj.Attributes["AllocId"].(uint16)
883
884 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
885 // otherwise we are adding it
886 if allocId == 255 || allocId == 65535 {
887 onuLogger.WithFields(log.Fields{
888 "IntfId": o.PonPortID,
889 "OnuId": o.ID,
890 "TContId": msgObj.EntityInstance,
891 "AllocId": allocId,
892 "SerialNumber": o.Sn(),
893 }).Trace("freeing-alloc-id-via-omci")
894 o.PonPort.removeAllocId(o.SerialNumber)
895 } else {
896 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
897 onuLogger.WithFields(log.Fields{
898 "IntfId": o.PonPortID,
899 "OnuId": o.ID,
900 "AllocId": allocId,
901 "SerialNumber": o.Sn(),
902 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
903 success = false
904 } else {
905 onuLogger.WithFields(log.Fields{
906 "IntfId": o.PonPortID,
907 "OnuId": o.ID,
908 "TContId": msgObj.EntityInstance,
909 "AllocId": allocId,
910 "SerialNumber": o.Sn(),
911 }).Trace("storing-alloc-id-via-omci")
912 o.PonPort.storeAllocId(allocId, o.SerialNumber)
913 }
914 }
915
916 }
917
918 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700919 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800920 o.MibDataSync++
921 }
922 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700923 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800924 }
925 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800926 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
927 var used bool
928 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700929 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800930 if err == nil {
931 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700932 // GemPort 4069 is reserved for multicast and shared across ONUs
933 if msgObj.EntityInstance != 4069 {
934 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
935 onuLogger.WithFields(log.Fields{
936 "IntfId": o.PonPortID,
937 "OnuId": o.ID,
938 "GemPortId": msgObj.EntityInstance,
939 "SerialNumber": o.Sn(),
940 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
941 } else {
942 onuLogger.WithFields(log.Fields{
943 "IntfId": o.PonPortID,
944 "OnuId": o.ID,
945 "GemPortId": msgObj.EntityInstance,
946 "SerialNumber": o.Sn(),
947 }).Trace("storing-gem-port-id-via-omci")
948 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
949 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800950 }
951 }
952 }
953
954 // if the gemPort is valid then increment the MDS and return a successful response
955 // otherwise fail the request
956 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
957 // validation this check will need to be rewritten
958 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700959 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800960 o.MibDataSync++
961 }
962 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700963 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800964 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800965 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700966 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800967 if err == nil {
968 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
969 onuLogger.WithFields(log.Fields{
970 "IntfId": o.PonPortID,
971 "OnuId": o.ID,
972 "GemPortId": msgObj.EntityInstance,
973 "SerialNumber": o.Sn(),
974 }).Trace("freeing-gem-port-id-via-omci")
975 o.PonPort.removeGemPort(msgObj.EntityInstance)
976 }
977 }
978
Matteo Scandolob5913142021-03-19 16:10:18 -0700979 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800980 o.MibDataSync++
981 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800982 case omci.RebootRequestType:
983
Matteo Scandolob5913142021-03-19 16:10:18 -0700984 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800985
986 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800987 // we run this in a separate goroutine so that
988 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800989 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800990 if err := o.Reboot(10 * time.Second); err != nil {
991 log.WithFields(log.Fields{
992 "IntfId": o.PonPortID,
993 "OnuId": o.ID,
994 "SerialNumber": o.Sn(),
995 "err": err,
996 }).Error("cannot-reboot-onu-after-omci-reboot-request")
997 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800998 }()
999 case omci.TestRequestType:
Girish Gowdra161d27a2021-05-05 12:01:44 -07001000 var classID me.ClassID
1001 var omciResult me.Results
1002 var instID uint16
1003 responsePkt, errResp, classID, instID, omciResult = omcilib.CreateTestResponse(msg.OmciPkt, msg.OmciMsg)
1004 // Send TestResult only in case the TestResponse omci result code is me.Success
1005 if responsePkt != nil && errResp == nil && omciResult == me.Success {
1006 if testResultPkt, err := omcilib.CreateTestResult(classID, instID, msg.OmciMsg.TransactionID); err == nil {
1007 // send test results asynchronously
1008 go func() {
1009 // Send test results after a second to emulate async behavior
1010 time.Sleep(1 * time.Second)
1011 if testResultPkt != nil {
1012 if err := o.sendOmciIndication(testResultPkt, msg.OmciMsg.TransactionID, stream); err != nil {
1013 onuLogger.WithFields(log.Fields{
1014 "IntfId": o.PonPortID,
1015 "SerialNumber": o.Sn(),
1016 "omciPacket": testResultPkt,
1017 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1018 "transCorrId": msg.OmciMsg.TransactionID,
1019 }).Errorf("failed-to-send-omci-message: %v", err)
1020 }
1021 }
1022 }()
Matteo Scandolof9d43412021-01-12 11:11:34 -08001023 }
1024 }
Girish Gowdraa539f522021-02-15 23:00:45 -08001025 case omci.SynchronizeTimeRequestType:
1026 // MDS counter increment is not required for this message type
Matteo Scandolob5913142021-03-19 16:10:18 -07001027 responsePkt, _ = omcilib.CreateSyncTimeResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -08001028 case omci.StartSoftwareDownloadRequestType:
1029
1030 o.ImageSoftwareReceivedSections = 0
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301031 o.ImageSectionData = []byte{}
Matteo Scandolob5913142021-03-19 16:10:18 -07001032 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
Matteo Scandolocedde462021-03-09 17:37:16 -08001033
Matteo Scandolob5913142021-03-19 16:10:18 -07001034 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001035 o.MibDataSync++
1036 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
1037 onuLogger.WithFields(log.Fields{
1038 "OnuId": o.ID,
1039 "IntfId": o.PonPortID,
1040 "OnuSn": o.Sn(),
1041 "Err": err.Error(),
1042 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
1043 }
1044 } else {
1045 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001046 "OmciMsgType": msg.OmciMsg.MessageType,
1047 "TransCorrId": msg.OmciMsg.TransactionID,
1048 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001049 "IntfId": o.PonPortID,
1050 "SerialNumber": o.Sn(),
1051 }).Error("error-while-processing-start-software-download-request")
1052 }
1053 case omci.DownloadSectionRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001054 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001055 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001056 "OmciMsgType": msg.OmciMsg.MessageType,
1057 "TransCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001058 "EntityInstance": msgObj.EntityInstance,
1059 "SectionNumber": msgObj.SectionNumber,
1060 "SectionData": msgObj.SectionData,
1061 }).Trace("received-download-section-request")
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001062 //Extracting the first 14 bytes to use as a version for this image.
1063 if o.ImageSoftwareReceivedSections == 0 {
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001064 o.InDownloadImageVersion = string(msgObj.SectionData[0:14])
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001065 }
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301066 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
Matteo Scandolocedde462021-03-09 17:37:16 -08001067 o.ImageSoftwareReceivedSections++
1068 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1069 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1070 onuLogger.WithFields(log.Fields{
1071 "OnuId": o.ID,
1072 "IntfId": o.PonPortID,
1073 "OnuSn": o.Sn(),
1074 "Err": err.Error(),
1075 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1076 }
1077 }
1078 }
1079 case omci.DownloadSectionRequestWithResponseType:
1080 // NOTE we only need to respond if an ACK is requested
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301081 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001082 onuLogger.WithFields(log.Fields{
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301083 "OmciMsgType": msg.OmciMsg.MessageType,
1084 "TransCorrId": msg.OmciMsg.TransactionID,
1085 "EntityInstance": msgObj.EntityInstance,
1086 "SectionNumber": msgObj.SectionNumber,
1087 "SectionData": msgObj.SectionData,
1088 }).Trace("received-download-section-request-with-response-type")
1089 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
1090 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1091
1092 if errResp != nil {
1093 onuLogger.WithFields(log.Fields{
1094 "OmciMsgType": msg.OmciMsg.MessageType,
1095 "TransCorrId": msg.OmciMsg.TransactionID,
1096 "Err": errResp.Error(),
1097 "IntfId": o.PonPortID,
1098 "SerialNumber": o.Sn(),
1099 }).Error("error-while-processing-create-download-section-response")
1100 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
1101 }
1102 o.ImageSoftwareReceivedSections++
Matteo Scandolocedde462021-03-09 17:37:16 -08001103 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001104 case omci.EndSoftwareDownloadRequestType:
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001105 success := o.handleEndSoftwareDownloadRequest(msg)
Matteo Scandolocedde462021-03-09 17:37:16 -08001106
Matteo Scandolocedde462021-03-09 17:37:16 -08001107 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001108 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001109 o.MibDataSync++
1110 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1111 onuLogger.WithFields(log.Fields{
1112 "OnuId": o.ID,
1113 "IntfId": o.PonPortID,
1114 "OnuSn": o.Sn(),
1115 "Err": err.Error(),
1116 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1117 }
1118 } else {
1119 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001120 "OmciMsgType": msg.OmciMsg.MessageType,
1121 "TransCorrId": msg.OmciMsg.TransactionID,
1122 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001123 "IntfId": o.PonPortID,
1124 "SerialNumber": o.Sn(),
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001125 }).Error("error-while-responding-to-end-software-download-request")
Matteo Scandolocedde462021-03-09 17:37:16 -08001126 }
1127 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001128 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001129 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1130 onuLogger.WithFields(log.Fields{
1131 "OnuId": o.ID,
1132 "IntfId": o.PonPortID,
1133 "OnuSn": o.Sn(),
1134 "Err": err.Error(),
1135 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1136 }
1137 }
1138 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001139 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001140 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001141 o.MibDataSync++
1142 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1143 onuLogger.WithFields(log.Fields{
1144 "OnuId": o.ID,
1145 "IntfId": o.PonPortID,
1146 "OnuSn": o.Sn(),
1147 "Err": err.Error(),
1148 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1149 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001150 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001151 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001152 previousActiveImage := o.ActiveImageVersion
1153 o.ActiveImageVersion = o.StandbyImageVersion
1154 o.StandbyImageVersion = previousActiveImage
Matteo Scandolocedde462021-03-09 17:37:16 -08001155 } else {
1156 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1157 }
1158 onuLogger.WithFields(log.Fields{
1159 "OnuId": o.ID,
1160 "IntfId": o.PonPortID,
1161 "OnuSn": o.Sn(),
1162 "ActiveImageEntityId": o.ActiveImageEntityId,
1163 "CommittedImageEntityId": o.CommittedImageEntityId,
1164 }).Info("onu-software-image-activated")
1165
1166 // powercycle the ONU
1167 // we run this in a separate goroutine so that
1168 // the ActivateSoftwareResponse is sent to VOLTHA
1169 // NOTE do we need to wait before rebooting?
1170 go func() {
1171 if err := o.Reboot(10 * time.Second); err != nil {
1172 log.WithFields(log.Fields{
1173 "IntfId": o.PonPortID,
1174 "OnuId": o.ID,
1175 "SerialNumber": o.Sn(),
1176 "err": err,
1177 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1178 }
1179 }()
1180 }
1181 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001182 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001183 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001184 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001185 // TODO validate that the image to commit is:
1186 // - active
1187 // - not already committed
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001188 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandolocedde462021-03-09 17:37:16 -08001189 o.CommittedImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001190 //committed becomes standby
1191 o.StandbyImageVersion = o.CommittedImageVersion
1192 o.CommittedImageVersion = o.ActiveImageVersion
Matteo Scandolocedde462021-03-09 17:37:16 -08001193 } else {
1194 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1195 }
1196 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1197 onuLogger.WithFields(log.Fields{
1198 "OnuId": o.ID,
1199 "IntfId": o.PonPortID,
1200 "OnuSn": o.Sn(),
1201 "Err": err.Error(),
1202 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1203 }
1204 onuLogger.WithFields(log.Fields{
1205 "OnuId": o.ID,
1206 "IntfId": o.PonPortID,
1207 "OnuSn": o.Sn(),
1208 "ActiveImageEntityId": o.ActiveImageEntityId,
1209 "CommittedImageEntityId": o.CommittedImageEntityId,
1210 }).Info("onu-software-image-committed")
1211 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301212 case omci.GetAllAlarmsRequestType:
1213 // Reset the alarm sequence number on receiving get all alarms request.
1214 o.onuAlarmsInfoLock.Lock()
1215 for key, alarmInfo := range o.onuAlarmsInfo {
1216 // reset the alarm sequence no
1217 alarmInfo.SequenceNo = 0
1218 o.onuAlarmsInfo[key] = alarmInfo
1219 }
1220 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001221 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301222 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001223 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301224 responsePkt = nil //Do not send any response for error case
1225 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001226 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001227 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001228 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1229 "omciPkt": msg.OmciPkt,
1230 "omciMsgType": msg.OmciMsg.MessageType,
1231 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001232 "IntfId": o.PonPortID,
1233 "SerialNumber": o.Sn(),
1234 }).Warnf("OMCI-message-not-supported")
1235 }
1236
1237 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001238 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001239 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001240 "IntfId": o.PonPortID,
1241 "SerialNumber": o.Sn(),
1242 "omciPacket": responsePkt,
1243 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1244 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001245 }).Errorf("failed-to-send-omci-message: %v", err)
1246 }
1247 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001248
Pragya Arya324337e2020-02-20 14:35:08 +05301249 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001250 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001251}
Pragya Arya324337e2020-02-20 14:35:08 +05301252
Matteo Scandolof9d43412021-01-12 11:11:34 -08001253// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1254func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1255 indication := &openolt.Indication_OmciInd{
1256 OmciInd: &openolt.OmciIndication{
1257 IntfId: o.PonPortID,
1258 OnuId: o.ID,
1259 Pkt: responsePkt,
1260 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001261 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001262 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1263 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001264 }
1265 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001266 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001267 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001268 "omciPacket": indication.OmciInd.Pkt,
1269 "transCorrId": txId,
1270 }).Trace("omci-message-sent")
1271 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001272}
1273
Matteo Scandolo8a574812021-05-20 15:18:53 -07001274// FindUniById retrieves a UNI by ID
1275func (o *Onu) FindUniById(uniID uint32) (*UniPort, error) {
1276 for _, u := range o.UniPorts {
1277 uni := u.(*UniPort)
1278 if uni.ID == uniID {
1279 return uni, nil
1280 }
Matteo Scandolo27428702019-10-11 16:21:16 -07001281 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001282 return nil, fmt.Errorf("cannot-find-uni-with-id-%d-on-onu-%s", uniID, o.Sn())
1283}
1284
Elia Battistonac63b112022-01-12 18:40:49 +01001285// FindPotsById retrieves a POTS port by ID
1286func (o *Onu) FindPotsById(uniID uint32) (*PotsPort, error) {
1287 for _, p := range o.PotsPorts {
1288 pots := p.(*PotsPort)
1289 if pots.ID == uniID {
1290 return pots, nil
1291 }
1292 }
1293 return nil, fmt.Errorf("cannot-find-pots-with-id-%d-on-onu-%s", uniID, o.Sn())
1294}
1295
Matteo Scandolo8a574812021-05-20 15:18:53 -07001296// FindUniByEntityId retrieves a uni by MeID (the OMCI entity ID)
1297func (o *Onu) FindUniByEntityId(meId uint16) (*UniPort, error) {
1298 entityId := omcilib.EntityID{}.FromUint16(meId)
1299 for _, u := range o.UniPorts {
1300 uni := u.(*UniPort)
1301 if uni.MeId.Equals(entityId) {
1302 return uni, nil
1303 }
1304 }
1305 return nil, fmt.Errorf("cannot-find-uni-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
Matteo Scandolo27428702019-10-11 16:21:16 -07001306}
1307
Elia Battistonac63b112022-01-12 18:40:49 +01001308// FindPotsByEntityId retrieves a POTS uni by MeID (the OMCI entity ID)
1309func (o *Onu) FindPotsByEntityId(meId uint16) (*PotsPort, error) {
1310 entityId := omcilib.EntityID{}.FromUint16(meId)
1311 for _, p := range o.PotsPorts {
1312 pots := p.(*PotsPort)
1313 if pots.MeId.Equals(entityId) {
1314 return pots, nil
1315 }
1316 }
1317 return nil, fmt.Errorf("cannot-find-pots-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
1318}
1319
William Kurkian0418bc82019-11-06 12:16:24 -05001320func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001321 onuLogger.WithFields(log.Fields{
1322 "IntfId": o.PonPortID,
1323 "OnuId": id,
1324 "SerialNumber": o.Sn(),
1325 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001326 o.ID = id
1327}
1328
Matteo Scandolof9d43412021-01-12 11:11:34 -08001329func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001330 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001331 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001332 "Cookie": msg.Flow.Cookie,
1333 "DstPort": msg.Flow.Classifier.DstPort,
1334 "FlowId": msg.Flow.FlowId,
1335 "FlowType": msg.Flow.FlowType,
1336 "GemportId": msg.Flow.GemportId,
1337 "InnerVlan": msg.Flow.Classifier.IVid,
1338 "IntfId": msg.Flow.AccessIntfId,
1339 "IpProto": msg.Flow.Classifier.IpProto,
1340 "OnuId": msg.Flow.OnuId,
1341 "OnuSn": o.Sn(),
1342 "OuterVlan": msg.Flow.Classifier.OVid,
1343 "PortNo": msg.Flow.PortNo,
1344 "SrcPort": msg.Flow.Classifier.SrcPort,
1345 "UniID": msg.Flow.UniId,
1346 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1347 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1348 "ClassifierIVid": msg.Flow.Classifier.IVid,
1349 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001350 "ReplicateFlow": msg.Flow.ReplicateFlow,
1351 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001352 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001353
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001354 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001355
1356 var gemPortId uint32
1357 if msg.Flow.ReplicateFlow {
1358 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1359 // first available gemport (we only need to send one packet)
1360 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1361 gemPortId = msg.Flow.PbitToGemport[0]
1362 } else {
1363 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1364 gemPortId = uint32(msg.Flow.GemportId)
1365 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001366
1367 uni, err := o.FindUniById(uint32(msg.Flow.UniId))
1368 if err != nil {
1369 onuLogger.WithFields(log.Fields{
1370 "IntfId": o.PonPortID,
1371 "OnuId": o.ID,
1372 "UniId": msg.Flow.UniId,
1373 "PortNo": msg.Flow.PortNo,
1374 "SerialNumber": o.Sn(),
1375 "FlowId": msg.Flow.FlowId,
1376 "FlowType": msg.Flow.FlowType,
1377 }).Error("cannot-find-uni-port-for-flow")
1378 }
1379
1380 uni.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
1381 uni.StorePortNo(msg.Flow.PortNo)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001382
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001383 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001384 uni.HandleAuth()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001385 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1386 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001387 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001388 uni.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001389 }
1390}
1391
Matteo Scandolof9d43412021-01-12 11:11:34 -08001392func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001393 onuLogger.WithFields(log.Fields{
1394 "IntfId": o.PonPortID,
1395 "OnuId": o.ID,
1396 "SerialNumber": o.Sn(),
1397 "FlowId": msg.Flow.FlowId,
1398 "FlowType": msg.Flow.FlowType,
1399 }).Debug("ONU receives FlowRemove")
1400
1401 for idx, flow := range o.FlowIds {
1402 // If the gemport is found, delete it from local cache.
1403 if flow == msg.Flow.FlowId {
1404 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1405 break
1406 }
1407 }
1408
1409 if len(o.FlowIds) == 0 {
1410 onuLogger.WithFields(log.Fields{
1411 "IntfId": o.PonPortID,
1412 "OnuId": o.ID,
1413 "SerialNumber": o.Sn(),
1414 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001415
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301416 // check if ONU delete is performed and
1417 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001418 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301419 close(o.Channel)
1420 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001421 }
1422}
1423
Matteo Scandolocedde462021-03-09 17:37:16 -08001424func (o *Onu) Reboot(timeout time.Duration) error {
1425 onuLogger.WithFields(log.Fields{
1426 "IntfId": o.PonPortID,
1427 "OnuId": o.ID,
1428 "SerialNumber": o.Sn(),
1429 }).Debug("shutting-down-onu")
1430 if err := o.HandleShutdownONU(); err != nil {
1431 return err
1432 }
1433 time.Sleep(timeout)
1434 onuLogger.WithFields(log.Fields{
1435 "IntfId": o.PonPortID,
1436 "OnuId": o.ID,
1437 "SerialNumber": o.Sn(),
1438 }).Debug("power-on-onu")
1439 if err := o.HandlePowerOnONU(); err != nil {
1440 return err
1441 }
1442 return nil
1443}
1444
Matteo Scandolo76f6b892021-11-15 16:13:06 -08001445// returns true if the request is successful, false otherwise
1446func (o *Onu) handleEndSoftwareDownloadRequest(msg bbsim.OmciMessage) bool {
1447 msgObj, err := omcilib.ParseEndSoftwareDownloadRequest(msg.OmciPkt)
1448 if err != nil {
1449 onuLogger.WithFields(log.Fields{
1450 "OmciMsgType": msg.OmciMsg.MessageType,
1451 "TransCorrId": msg.OmciMsg.TransactionID,
1452 "Err": err.Error(),
1453 "IntfId": o.PonPortID,
1454 "SerialNumber": o.Sn(),
1455 }).Error("error-while-processing-end-software-download-request")
1456 return false
1457 }
1458
1459 onuLogger.WithFields(log.Fields{
1460 "OnuId": o.ID,
1461 "IntfId": o.PonPortID,
1462 "OnuSn": o.Sn(),
1463 "msgObj": msgObj,
1464 }).Trace("EndSoftwareDownloadRequest received message")
1465
1466 // if the image download is ongoing and we receive a message with
1467 // ImageSize = 0 and Crc = 4294967295 (0xFFFFFFFF) respond with success
1468 if o.ImageSoftwareReceivedSections > 0 &&
1469 msgObj.ImageSize == 0 &&
1470 msgObj.CRC32 == 4294967295 {
1471 o.ImageSoftwareReceivedSections = 0
1472 // NOTE potentially we may want to add a ONU state to reflect
1473 // the software download abort
1474 return true
1475 }
1476
1477 // In the startSoftwareDownload we get the image size and the window size.
1478 // We calculate how many DownloadSection we should receive and validate
1479 // that we got the correct amount when we receive this message
1480 // If the received sections are different from the expected sections
1481 // respond with failure
1482 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1483 onuLogger.WithFields(log.Fields{
1484 "OnuId": o.ID,
1485 "IntfId": o.PonPortID,
1486 "OnuSn": o.Sn(),
1487 "ExpectedSections": o.ImageSoftwareExpectedSections,
1488 "ReceivedSections": o.ImageSoftwareReceivedSections,
1489 }).Errorf("onu-did-not-receive-all-image-sections")
1490 return false
1491 }
1492
1493 // check the received CRC vs the computed CRC
1494 computedCRC := crc32a.Checksum(o.ImageSectionData[:int(msgObj.ImageSize)])
1495 //Convert the crc to network byte order
1496 var byteSlice = make([]byte, 4)
1497 binary.LittleEndian.PutUint32(byteSlice, computedCRC)
1498 computedCRC = binary.BigEndian.Uint32(byteSlice)
1499 if msgObj.CRC32 != computedCRC {
1500 onuLogger.WithFields(log.Fields{
1501 "OnuId": o.ID,
1502 "IntfId": o.PonPortID,
1503 "OnuSn": o.Sn(),
1504 "ReceivedCRC": msgObj.CRC32,
1505 "CalculatedCRC": computedCRC,
1506 }).Errorf("onu-image-crc-validation-failed")
1507 return false
1508 }
1509
1510 o.StandbyImageVersion = o.InDownloadImageVersion
1511 onuLogger.WithFields(log.Fields{
1512 "OnuId": o.ID,
1513 "IntfId": o.PonPortID,
1514 "OnuSn": o.Sn(),
1515 "StandbyVersion": o.StandbyImageVersion,
1516 }).Debug("onu-image-version-updated")
1517 return true
1518}
1519
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001520// BBR methods
1521
1522func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1523 omciMsg := openolt.OmciMsg{
1524 IntfId: intfId,
1525 OnuId: onuId,
1526 Pkt: pktBytes,
1527 }
1528
1529 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1530 log.WithFields(log.Fields{
1531 "IntfId": intfId,
1532 "OnuId": onuId,
1533 "SerialNumber": common.OnuSnToString(sn),
1534 "Pkt": omciMsg.Pkt,
1535 }).Fatalf("Failed to send MIB Reset")
1536 }
1537 log.WithFields(log.Fields{
1538 "IntfId": intfId,
1539 "OnuId": onuId,
1540 "SerialNumber": common.OnuSnToString(sn),
1541 "Pkt": omciMsg.Pkt,
1542 }).Tracef("Sent OMCI message %s", msgType)
1543}
1544
1545func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1546 var next uint16
1547 if len(highPriority) > 0 && highPriority[0] {
1548 next = onu.hpTid
1549 onu.hpTid += 1
1550 if onu.hpTid < 0x8000 {
1551 onu.hpTid = 0x8000
1552 }
1553 } else {
1554 next = onu.tid
1555 onu.tid += 1
1556 if onu.tid >= 0x8000 {
1557 onu.tid = 1
1558 }
1559 }
1560 return next
1561}
1562
1563// TODO move this method in responders/omcisim
Matteo Scandolo8a574812021-05-20 15:18:53 -07001564// StartOmci is called in BBR to start the OMCI state machine
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001565func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1566 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1567 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1568}
1569
Matteo Scandolof9d43412021-01-12 11:11:34 -08001570// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1571func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1572
1573 // we need to encode the packet in HEX
1574 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1575 hex.Encode(pkt, msg.OmciInd.Pkt)
1576 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1577 if err != nil {
1578 log.WithFields(log.Fields{
1579 "IntfId": o.PonPortID,
1580 "SerialNumber": o.Sn(),
1581 "omciPacket": msg.OmciInd.Pkt,
1582 }).Error("BBR Cannot parse OMCI packet")
1583 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001584
1585 log.WithFields(log.Fields{
1586 "IntfId": msg.OmciInd.IntfId,
1587 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001588 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001589 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001590 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301591 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001592 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001593 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001594 log.WithFields(log.Fields{
1595 "IntfId": msg.OmciInd.IntfId,
1596 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001597 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001598 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001599 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001600 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001601 case omci.MibResetResponseType:
1602 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1603 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1604 case omci.MibUploadResponseType:
1605 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1606 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1607 case omci.MibUploadNextResponseType:
1608 o.seqNumber++
Matteo Scandolo8a574812021-05-20 15:18:53 -07001609 // once the mibUpload is complete send a SetRequest for the PPTP to enable the UNI
1610 // NOTE that in BBR we only enable the first UNI
1611 if o.seqNumber == o.MibDb.NumberOfCommands {
1612 meId := omcilib.GenerateUniPortEntityId(1)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001613
Matteo Scandolo8a574812021-05-20 15:18:53 -07001614 meParams := me.ParamData{
1615 EntityID: meId.ToUint16(),
1616 Attributes: me.AttributeValueMap{"AdministrativeState": 0},
1617 }
1618 managedEntity, omciError := me.NewPhysicalPathTerminationPointEthernetUni(meParams)
1619 if omciError.GetError() != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001620 onuLogger.WithFields(log.Fields{
1621 "OnuId": o.ID,
1622 "IntfId": o.PonPortID,
1623 "OnuSn": o.Sn(),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001624 }).Fatal(omciError.GetError())
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001625 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001626
1627 setPPtp, _ := omcilib.CreateSetRequest(managedEntity, 1)
1628 sendOmciMsg(setPPtp, o.PonPortID, o.ID, o.SerialNumber, "setRquest", client)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001629 } else {
1630 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1631 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001632 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001633 case omci.SetResponseType:
1634 // once we set the PPTP to active we can start sending flows
1635
1636 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
1637 onuLogger.WithFields(log.Fields{
1638 "OnuId": o.ID,
1639 "IntfId": o.PonPortID,
1640 "OnuSn": o.Sn(),
1641 }).Errorf("Error while transitioning ONU State %v", err)
1642 }
1643 case omci.AlarmNotificationType:
1644 log.Info("bbr-received-alarm")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001645 }
1646}
1647
1648func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1649
1650 classifierProto := openolt.Classifier{
1651 EthType: uint32(layers.EthernetTypeEAPOL),
1652 OVid: 4091,
1653 }
1654
1655 actionProto := openolt.Action{}
1656
1657 downstreamFlow := openolt.Flow{
1658 AccessIntfId: int32(o.PonPortID),
1659 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001660 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001661 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001662 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001663 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001664 Classifier: &classifierProto,
1665 Action: &actionProto,
1666 Priority: int32(100),
1667 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001668 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1669 // AllocId and GemPorts need to be unique per PON
1670 // for now use the ONU-ID, will need to change once we support multiple UNIs
1671 AllocId: int32(o.ID),
1672 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001673 }
1674
1675 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1676 log.WithFields(log.Fields{
1677 "IntfId": o.PonPortID,
1678 "OnuId": o.ID,
1679 "FlowId": downstreamFlow.FlowId,
1680 "PortNo": downstreamFlow.PortNo,
1681 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001682 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001683 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001684 }
1685 log.WithFields(log.Fields{
1686 "IntfId": o.PonPortID,
1687 "OnuId": o.ID,
1688 "FlowId": downstreamFlow.FlowId,
1689 "PortNo": downstreamFlow.PortNo,
1690 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1691 }).Info("Sent EAPOL Flow")
1692}
1693
1694func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001695
Matteo Scandolo8a574812021-05-20 15:18:53 -07001696 // BBR only works with a single UNI and a single service (ATT HSIA)
1697 hsia := o.UniPorts[0].(*UniPort).Services[0].(*Service)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001698 classifierProto := openolt.Classifier{
1699 EthType: uint32(layers.EthernetTypeIPv4),
1700 SrcPort: uint32(68),
1701 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001702 OVid: uint32(hsia.CTag),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001703 OPbits: 255,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001704 }
1705
1706 actionProto := openolt.Action{}
1707
1708 downstreamFlow := openolt.Flow{
1709 AccessIntfId: int32(o.PonPortID),
1710 OnuId: int32(o.ID),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001711 UniId: int32(0), // BBR only supports a single UNI
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001712 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001713 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001714 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001715 Classifier: &classifierProto,
1716 Action: &actionProto,
1717 Priority: int32(100),
1718 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001719 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1720 // AllocId and GemPorts need to be unique per PON
1721 // for now use the ONU-ID, will need to change once we support multiple UNIs
1722 AllocId: int32(o.ID),
1723 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001724 }
1725
1726 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1727 log.WithFields(log.Fields{
1728 "IntfId": o.PonPortID,
1729 "OnuId": o.ID,
1730 "FlowId": downstreamFlow.FlowId,
1731 "PortNo": downstreamFlow.PortNo,
1732 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001733 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001734 }).Fatalf("Failed to send DHCP Flow")
1735 }
1736 log.WithFields(log.Fields{
1737 "IntfId": o.PonPortID,
1738 "OnuId": o.ID,
1739 "FlowId": downstreamFlow.FlowId,
1740 "PortNo": downstreamFlow.PortNo,
1741 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1742 }).Info("Sent DHCP Flow")
1743}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301744
yasin saplid4445982022-01-25 09:30:30 +00001745// DeleteFlow method search and delete flowId from the onu flowIds slice
1746func (onu *Onu) DeleteFlow(id uint64) {
1747 for pos, flowId := range onu.FlowIds {
1748 if flowId == id {
1749 // delete the flowId by shifting all flowIds by one
1750 onu.FlowIds = append(onu.FlowIds[:pos], onu.FlowIds[pos+1:]...)
Pragya Arya8bdb4532020-03-02 17:08:09 +05301751 break
1752 }
1753 }
1754}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301755
1756func (onu *Onu) ReDiscoverOnu() {
1757 // Wait for few seconds to be sure of the cleanup
1758 time.Sleep(5 * time.Second)
1759
1760 onuLogger.WithFields(log.Fields{
1761 "IntfId": onu.PonPortID,
1762 "OnuId": onu.ID,
1763 "OnuSn": onu.Sn(),
1764 }).Debug("Send ONU Re-Discovery")
1765
1766 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001767 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301768 log.WithFields(log.Fields{
1769 "IntfId": onu.PonPortID,
1770 "OnuSn": onu.Sn(),
1771 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001772 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301773 }
1774
Matteo Scandolocedde462021-03-09 17:37:16 -08001775 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301776 log.WithFields(log.Fields{
1777 "IntfId": onu.PonPortID,
1778 "OnuSn": onu.Sn(),
1779 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001780 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301781 }
1782}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001783
Matteo Scandolo8a574812021-05-20 15:18:53 -07001784// deprecated, delegate this to the uniPort
Matteo Scandolo4a036262020-08-17 15:56:13 -07001785func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001786 // FIXME is there a better way to avoid this loop?
1787 for _, u := range onu.UniPorts {
1788 uni := u.(*UniPort)
1789 for _, s := range uni.Services {
1790 service := s.(*Service)
1791 if service.HwAddress.String() == macAddress.String() {
1792 return service, nil
1793 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001794 }
1795 }
1796 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1797}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301798
Matteo Scandolo8a574812021-05-20 15:18:53 -07001799func (onu *Onu) findUniByPortNo(portNo uint32) (*UniPort, error) {
1800 for _, u := range onu.UniPorts {
1801 uni := u.(*UniPort)
1802 if uni.PortNo == portNo {
1803 return uni, nil
1804 }
1805 }
1806 return nil, fmt.Errorf("cannot-find-uni-with-port-no-%d", portNo)
1807}
1808
Himani Chawla13b1ee02021-03-15 01:43:53 +05301809func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1810 switch alarmType {
1811 case "ONU_ALARM_LOS":
1812 msg := bbsim.Message{
1813 Type: bbsim.UniStatusAlarm,
1814 Data: bbsim.UniStatusAlarmMessage{
1815 OnuSN: o.SerialNumber,
1816 OnuID: o.ID,
1817 EntityID: 257,
1818 RaiseOMCIAlarm: raiseOMCIAlarm,
1819 },
1820 }
1821 o.Channel <- msg
1822 }
1823
1824}
1825
1826func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1827 o.onuAlarmsInfoLock.Lock()
1828 defer o.onuAlarmsInfoLock.Unlock()
1829 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1830 if alarmInfo.SequenceNo == 255 {
1831 alarmInfo.SequenceNo = 1
1832 } else {
1833 alarmInfo.SequenceNo++
1834 }
1835 o.onuAlarmsInfo[key] = alarmInfo
1836 return alarmInfo.SequenceNo
1837 } else {
1838 // This is the first time alarm notification message is being sent
1839 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1840 SequenceNo: 1,
1841 }
1842 return 1
1843 }
1844}
Elia Battistonfe017662022-01-05 11:43:16 +01001845
1846func (o *Onu) InvalidateMibDataSync() {
1847 rand.Seed(time.Now().UnixNano())
1848 r := uint8(rand.Intn(10) + 1)
1849
1850 o.MibDataSync += r
1851
1852 // Since MibDataSync is a uint8, summing to it will never
1853 // result in a value higher than 255, but could be 0
1854 if o.MibDataSync == 0 {
1855 o.MibDataSync++
1856 }
1857}