blob: 11ace9fbbc7b82f538684c3d8f0679c616cdc13f [file] [log] [blame]
Matteo Scandolo11006992019-08-28 11:29:46 -07001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Matteo Scandolo4747d292019-08-05 11:50:18 -070017package devices
18
19import (
Matteo Scandolo40e067f2019-10-16 16:59:41 -070020 "context"
Himani Chawla4ff5fab2021-11-09 19:19:29 +053021 "encoding/binary"
Matteo Scandolo618a6582020-09-09 12:21:29 -070022 "encoding/hex"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070023 "fmt"
Mahir Gunyela1753ae2021-06-23 00:24:56 -070024 "sync"
25
Matteo Scandolo8a574812021-05-20 15:18:53 -070026 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
27 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
28 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000029
Matteo Scandolof9d43412021-01-12 11:11:34 -080030 pb "github.com/opencord/bbsim/api/bbsim"
31 "github.com/opencord/bbsim/internal/bbsim/alarmsim"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000032
33 "net"
34 "strconv"
35 "time"
Himani Chawla13b1ee02021-03-15 01:43:53 +053036
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080037 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Andrea Campanella10426e22021-10-15 17:58:04 +020038 me "github.com/opencord/omci-lib-go/v2/generated"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010039
Himani Chawla4ff5fab2021-11-09 19:19:29 +053040 "github.com/boguslaw-wojcik/crc32a"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070041 "github.com/google/gopacket/layers"
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070042 "github.com/jpillora/backoff"
Matteo Scandolo4747d292019-08-05 11:50:18 -070043 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070044 "github.com/opencord/bbsim/internal/common"
45 omcilib "github.com/opencord/bbsim/internal/common/omci"
Andrea Campanella10426e22021-10-15 17:58:04 +020046 "github.com/opencord/omci-lib-go/v2"
David K. Bainbridgec415efe2021-08-19 13:05:21 +000047 "github.com/opencord/voltha-protos/v5/go/openolt"
48 "github.com/opencord/voltha-protos/v5/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070049 log "github.com/sirupsen/logrus"
50)
51
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070052var onuLogger = log.WithFields(log.Fields{
53 "module": "ONU",
54})
55
Matteo Scandolocedde462021-03-09 17:37:16 -080056const (
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000057 maxOmciMsgCounter = 10
58)
59
60const (
Matteo Scandolocedde462021-03-09 17:37:16 -080061 // ONU transitions
62 OnuTxInitialize = "initialize"
63 OnuTxDiscover = "discover"
64 OnuTxEnable = "enable"
65 OnuTxDisable = "disable"
66 OnuTxPonDisable = "pon_disable"
67 OnuTxStartImageDownload = "start_image_download"
68 OnuTxProgressImageDownload = "progress_image_download"
69 OnuTxCompleteImageDownload = "complete_image_download"
70 OnuTxFailImageDownload = "fail_image_download"
71 OnuTxActivateImage = "activate_image"
72 OnuTxCommitImage = "commit_image"
73
74 // ONU States
75 OnuStateCreated = "created"
76 OnuStateInitialized = "initialized"
77 OnuStateDiscovered = "discovered"
78 OnuStateEnabled = "enabled"
79 OnuStateDisabled = "disabled"
80 OnuStatePonDisabled = "pon_disabled"
81 OnuStateImageDownloadStarted = "image_download_started"
82 OnuStateImageDownloadInProgress = "image_download_in_progress"
83 OnuStateImageDownloadComplete = "image_download_completed"
84 OnuStateImageDownloadError = "image_download_error"
85 OnuStateImageActivated = "software_image_activated"
86 OnuStateImageCommitted = "software_image_committed"
87
88 // BBR ONU States and Transitions
89 BbrOnuTxSendEapolFlow = "send_eapol_flow"
90 BbrOnuStateEapolFlowSent = "eapol_flow_sent"
91 BbrOnuTxSendDhcpFlow = "send_dhcp_flow"
92 BbrOnuStateDhcpFlowSent = "dhcp_flow_sent"
93)
94
Pragya Arya8bdb4532020-03-02 17:08:09 +053095type FlowKey struct {
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070096 ID uint64
Pragya Arya8bdb4532020-03-02 17:08:09 +053097 Direction string
98}
99
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700100type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800101 ID uint32
102 PonPortID uint32
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700103 PonPort *PonPort
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800104 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +0530105 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
106 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandolo4a036262020-08-17 15:56:13 -0700107
Matteo Scandolo4a036262020-08-17 15:56:13 -0700108 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800109 // ONU State
Matteo Scandolo8a574812021-05-20 15:18:53 -0700110 UniPorts []UniPortIf
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700111 Flows []FlowKey
112 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700113
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700114 OperState *fsm.FSM
115 SerialNumber *openolt.SerialNumber
116
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700117 AdminLockState uint8 // 0 is enabled, 1 is disabled.
118
Matteo Scandolof9d43412021-01-12 11:11:34 -0800119 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700120
121 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800122 MibDataSync uint8
123 ImageSoftwareExpectedSections int
124 ImageSoftwareReceivedSections int
125 ActiveImageEntityId uint16
126 CommittedImageEntityId uint16
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700127 StandbyImageVersion string
128 ActiveImageVersion string
129 CommittedImageVersion string
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000130 OmciResponseRate uint8
131 OmciMsgCounter uint8
Himani Chawla4ff5fab2021-11-09 19:19:29 +0530132 ImageSectionData []byte
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800133
134 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700135 tid uint16
136 hpTid uint16
137 seqNumber uint16
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700138 MibDb *omcilib.MibDb
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700139
Anand S Katti09541352020-01-29 15:54:01 +0530140 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
141 TrafficSchedulers *tech_profile.TrafficSchedulers
Himani Chawla13b1ee02021-03-15 01:43:53 +0530142 onuAlarmsInfoLock sync.RWMutex
143 onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700144}
145
Matteo Scandolo99f18462019-10-28 14:14:28 -0700146func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700147 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700148}
149
Matteo Scandolo8a574812021-05-20 15:18:53 -0700150func 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 -0700151
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700152 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800153 ID: id,
154 PonPortID: pon.ID,
155 PonPort: pon,
Matteo Scandolocedde462021-03-09 17:37:16 -0800156 tid: 0x1,
157 hpTid: 0x8000,
158 seqNumber: 0,
159 DoneChannel: make(chan bool, 1),
160 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
161 Flows: []FlowKey{},
162 DiscoveryDelay: delay,
163 MibDataSync: 0,
164 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
165 ImageSoftwareReceivedSections: 0,
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700166 //TODO this needs reworking, it's always 0 or 1, possibly base all on the version
167 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
168 CommittedImageEntityId: 0,
169 StandbyImageVersion: "BBSM_IMG_00000",
170 ActiveImageVersion: "BBSM_IMG_00001",
171 CommittedImageVersion: "BBSM_IMG_00001",
172 OmciResponseRate: olt.OmciResponseRate,
173 OmciMsgCounter: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700174 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800175 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700176 // NOTE this state machine is used to track the operational
177 // state as requested by VOLTHA
178 o.OperState = getOperStateFSM(func(e *fsm.Event) {
179 onuLogger.WithFields(log.Fields{
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700180 "OnuId": o.ID,
181 "IntfId": o.PonPortID,
182 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700183 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
184 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530185 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700186 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
187 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800188 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700189 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700190 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800191 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
192 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
193 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100194 // 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 -0800195 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530196 // 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 +0200197 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted, OnuStateImageDownloadComplete}, Dst: OnuStatePonDisabled},
Matteo Scandolocedde462021-03-09 17:37:16 -0800198 // Software Image Download related states
Matteo Scandolo9f4bf4f2021-06-22 09:41:02 +0200199 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateImageDownloadStarted},
Matteo Scandolocedde462021-03-09 17:37:16 -0800200 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
201 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
202 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
203 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
204 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700205 // BBR States
206 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800207 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
208 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700209 },
210 fsm.Callbacks{
211 "enter_state": func(e *fsm.Event) {
212 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700213 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700214 fmt.Sprintf("enter_%s", OnuStateInitialized): func(e *fsm.Event) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100215 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800216 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800217
Matteo Scandolocedde462021-03-09 17:37:16 -0800218 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800219 onuLogger.WithFields(log.Fields{
220 "OnuId": o.ID,
221 "IntfId": o.PonPortID,
222 "OnuSn": o.Sn(),
223 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
224 }
225
Pragya Arya1cbefa42020-01-13 12:15:29 +0530226 if !isMock {
227 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700228 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530229 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100230 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700231 fmt.Sprintf("enter_%s", OnuStateDiscovered): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800232 msg := bbsim.Message{
233 Type: bbsim.OnuDiscIndication,
234 Data: bbsim.OnuDiscIndicationMessage{
235 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100236 },
237 }
238 o.Channel <- msg
239 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700240 fmt.Sprintf("enter_%s", OnuStateEnabled): func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800241
242 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
243 onuLogger.WithFields(log.Fields{
244 "IntfId": o.PonPortID,
245 "OnuId": o.ID,
246 "SerialNumber": o.Sn(),
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700247 }).Errorf("onu-id-duplicated-with-%s", common.OnuSnToString(sn))
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800248 return
249 } else {
250 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
251 }
252
Matteo Scandolof9d43412021-01-12 11:11:34 -0800253 msg := bbsim.Message{
254 Type: bbsim.OnuIndication,
255 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700256 OnuSN: o.SerialNumber,
257 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800258 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700259 },
260 }
261 o.Channel <- msg
262 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700263 fmt.Sprintf("enter_%s", OnuStateDisabled): func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700264
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700265 o.cleanupOnuState()
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700266
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700267 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800268 if err := o.OperState.Event("disable"); err != nil {
269 onuLogger.WithFields(log.Fields{
270 "OnuId": o.ID,
271 "IntfId": o.PonPortID,
272 "OnuSn": o.Sn(),
273 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
274 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700275 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800276 msg := bbsim.Message{
277 Type: bbsim.OnuIndication,
278 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700279 OnuSN: o.SerialNumber,
280 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800281 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700282 },
283 }
284 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530285
Matteo Scandolo8a574812021-05-20 15:18:53 -0700286 // disable the UNI ports
287 for _, uni := range o.UniPorts {
288 _ = uni.Disable()
289 }
290
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530291 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100292 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolo8a574812021-05-20 15:18:53 -0700293 // NOTE may need to wait for the UNIs to be down too before shutting down the channel
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530294 if len(o.FlowIds) == 0 {
295 close(o.Channel)
296 }
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700297 },
298 fmt.Sprintf("enter_%s", OnuStatePonDisabled): func(event *fsm.Event) {
299 o.cleanupOnuState()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700300 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700301 // BBR states
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700302 fmt.Sprintf("enter_%s", BbrOnuStateEapolFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800303 msg := bbsim.Message{
304 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700305 }
306 o.Channel <- msg
307 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700308 fmt.Sprintf("enter_%s", BbrOnuStateDhcpFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800309 msg := bbsim.Message{
310 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700311 }
312 o.Channel <- msg
313 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700314 },
315 )
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700316 onuLogger.WithFields(log.Fields{
317 "OnuId": o.ID,
318 "IntfId": o.PonPortID,
319 "OnuSn": o.Sn(),
320 "NumUni": olt.NumUni,
321 }).Debug("creating-uni-ports")
322 for i := 0; i < olt.NumUni; i++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700323 uni, err := NewUniPort(uint32(i), &o, nextCtag, nextStag)
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700324 if err != nil {
325 onuLogger.WithFields(log.Fields{
326 "OnuId": o.ID,
327 "IntfId": o.PonPortID,
328 "OnuSn": o.Sn(),
329 "Err": err,
330 }).Fatal("cannot-create-uni-port")
331 }
332 o.UniPorts = append(o.UniPorts, uni)
333 }
334
335 mibDb, err := omcilib.GenerateMibDatabase(len(o.UniPorts))
336 if err != nil {
337 onuLogger.WithFields(log.Fields{
338 "OnuId": o.ID,
339 "IntfId": o.PonPortID,
340 "OnuSn": o.Sn(),
341 }).Fatal("cannot-generate-mibdb-for-onu")
342 }
343 o.MibDb = mibDb
344
Matteo Scandolo27428702019-10-11 16:21:16 -0700345 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700346}
347
William Kurkian0418bc82019-11-06 12:16:24 -0500348func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700349 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700350 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700351 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700352 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700353 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
354}
355
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700356// cleanupOnuState this method is to clean the local state when the ONU is disabled
357func (o *Onu) cleanupOnuState() {
358 // clean the ONU state
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700359 o.Flows = []FlowKey{}
360 o.PonPort.removeOnuId(o.ID)
361 o.PonPort.removeAllocId(o.SerialNumber)
362 o.PonPort.removeGemPortBySn(o.SerialNumber)
363
364 o.onuAlarmsInfoLock.Lock()
365 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
366 o.onuAlarmsInfoLock.Unlock()
367}
368
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100369// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000370func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700371 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100372 "onuID": o.ID,
373 "onuSN": o.Sn(),
374 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700375 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100376 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700377
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700378 defer onuLogger.WithFields(log.Fields{
379 "onuID": o.ID,
380 "onuSN": o.Sn(),
381 "stream": stream,
382 }).Debug("Stopped handling ONU Indication Channel")
383
David Bainbridge103cf022019-12-16 20:11:35 +0000384loop:
385 for {
386 select {
387 case <-ctx.Done():
388 onuLogger.WithFields(log.Fields{
389 "onuID": o.ID,
390 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700391 }).Debug("ONU message handling canceled via context")
392 break loop
393 case <-stream.Context().Done():
394 onuLogger.WithFields(log.Fields{
395 "onuID": o.ID,
396 "onuSN": o.Sn(),
397 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000398 break loop
399 case message, ok := <-o.Channel:
400 if !ok || ctx.Err() != nil {
401 onuLogger.WithFields(log.Fields{
402 "onuID": o.ID,
403 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700404 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000405 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700406 }
David Bainbridge103cf022019-12-16 20:11:35 +0000407 onuLogger.WithFields(log.Fields{
408 "onuID": o.ID,
409 "onuSN": o.Sn(),
410 "messageType": message.Type,
411 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700412
David Bainbridge103cf022019-12-16 20:11:35 +0000413 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800414 case bbsim.OnuDiscIndication:
415 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000416 // 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 +0530417 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000418 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800419 case bbsim.OnuIndication:
420 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000421 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800422 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800423 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800424 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200425 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800426 case bbsim.UniStatusAlarm:
427 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530428 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
429 MeInstance: msg.EntityID,
430 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
431 }
432 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
433 o.onuAlarmsInfoLock.Lock()
434 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
435 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
436 if pkt != nil { //pkt will be nil if we are unable to create the alarm
437 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
438 onuLogger.WithFields(log.Fields{
439 "IntfId": o.PonPortID,
440 "SerialNumber": o.Sn(),
441 "omciPacket": pkt,
442 "adminState": msg.AdminState,
443 "entityID": msg.EntityID,
444 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
445 alarmInfo.SequenceNo--
446 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800447 onuLogger.WithFields(log.Fields{
448 "IntfId": o.PonPortID,
449 "SerialNumber": o.Sn(),
450 "omciPacket": pkt,
451 "adminState": msg.AdminState,
452 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530453 }).Trace("UNI-Link-alarm-sent")
454 if alarmBitMap == [28]byte{0} {
455 delete(o.onuAlarmsInfo, onuAlarmMapKey)
456 } else {
457 alarmInfo.AlarmBitMap = alarmBitMap
458 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
459 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800460 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530461 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800462 case bbsim.FlowAdd:
463 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700464 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800465 case bbsim.FlowRemoved:
466 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700467 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800468 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700469
Matteo Scandolof9d43412021-01-12 11:11:34 -0800470 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000471
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700472 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000473 "IntfId": msg.IntfId,
474 "OnuId": msg.OnuId,
475 "pktType": msg.Type,
476 }).Trace("Received OnuPacketOut Message")
477
Matteo Scandolo8a574812021-05-20 15:18:53 -0700478 uni, err := o.findUniByPortNo(msg.PortNo)
Matteo Scandolo618a6582020-09-09 12:21:29 -0700479
Matteo Scandolo8a574812021-05-20 15:18:53 -0700480 if err != nil {
481 onuLogger.WithFields(log.Fields{
482 "IntfId": msg.IntfId,
483 "OnuId": msg.OnuId,
484 "pktType": msg.Type,
485 "portNo": msg.PortNo,
486 "MacAddress": msg.MacAddress,
487 "Pkt": hex.EncodeToString(msg.Packet.Data()),
488 "OnuSn": o.Sn(),
489 }).Error("Cannot find Uni associated with packet")
490 return
David Bainbridge103cf022019-12-16 20:11:35 +0000491 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700492 uni.PacketCh <- msg
493 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800494 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000495 // NOTE we only receive BBR packets here.
496 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
497 // 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 -0800498 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000499
Matteo Scandolo8a574812021-05-20 15:18:53 -0700500 onuLogger.WithFields(log.Fields{
501 "IntfId": msg.IntfId,
502 "OnuId": msg.OnuId,
503 "PortNo": msg.PortNo,
504 "GemPortId": msg.GemPortId,
505 "pktType": msg.Type,
David Bainbridge103cf022019-12-16 20:11:35 +0000506 }).Trace("Received OnuPacketIn Message")
507
Matteo Scandolo8a574812021-05-20 15:18:53 -0700508 uni, err := o.findUniByPortNo(msg.PortNo)
509 if err != nil {
510 onuLogger.WithFields(log.Fields{
511 "IntfId": msg.IntfId,
512 "OnuId": msg.OnuId,
513 "PortNo": msg.PortNo,
514 "GemPortId": msg.GemPortId,
515 "pktType": msg.Type,
516 }).Error(err.Error())
517 }
518
519 // BBR has one service and one UNI
520 serviceId := uint32(0)
521 oltId := 0
David Bainbridge103cf022019-12-16 20:11:35 +0000522 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700523 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 +0000524 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700525 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000526 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800527 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800528 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800529 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
530 o.handleOmciResponse(msg, client)
531 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000532 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800533 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000534 o.sendDhcpFlow(client)
535 default:
536 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700537 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700538 }
539 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700540}
541
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800542func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700543 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700544 sn.VendorId = []byte("BBSM")
545 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700546 return sn
547}
548
Matteo Scandolof9d43412021-01-12 11:11:34 -0800549func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700550 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800551 IntfId: o.PonPortID,
552 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700553 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700554
Matteo Scandolo4747d292019-08-05 11:50:18 -0700555 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700556 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700557 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700558 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700559
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700560 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800561 "IntfId": o.PonPortID,
562 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700563 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700564 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800565 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800566
567 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
568 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800569 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800570 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800571 o.sendOnuDiscIndication(msg, stream)
572 }
573 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700574}
575
Matteo Scandolof9d43412021-01-12 11:11:34 -0800576func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800577 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
578 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700579
580 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700581 IntfId: o.PonPortID,
582 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700583 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700584 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700585 SerialNumber: o.SerialNumber,
586 }}
587 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800588 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700589 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700590 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700591 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700592 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800593 "IntfId": o.PonPortID,
594 "OnuId": o.ID,
595 "VolthaOnuId": msg.OnuID,
596 "OperState": msg.OperState.String(),
597 "AdminState": msg.OperState.String(),
598 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700599 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700600
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700601}
602
Matteo Scandolof9d43412021-01-12 11:11:34 -0800603func (o *Onu) HandleShutdownONU() error {
604
605 dyingGasp := pb.ONUAlarmRequest{
606 AlarmType: "DYING_GASP",
607 SerialNumber: o.Sn(),
608 Status: "on",
609 }
610
611 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
612 onuLogger.WithFields(log.Fields{
613 "OnuId": o.ID,
614 "IntfId": o.PonPortID,
615 "OnuSn": o.Sn(),
616 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
617 return err
618 }
619
620 losReq := pb.ONUAlarmRequest{
621 AlarmType: "ONU_ALARM_LOS",
622 SerialNumber: o.Sn(),
623 Status: "on",
624 }
625
626 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
627 onuLogger.WithFields(log.Fields{
628 "OnuId": o.ID,
629 "IntfId": o.PonPortID,
630 "OnuSn": o.Sn(),
631 }).Errorf("Cannot send LOS: %s", err.Error())
632
633 return err
634 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530635 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800636 // TODO if it's the last ONU on the PON, then send a PON LOS
637
Matteo Scandolocedde462021-03-09 17:37:16 -0800638 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800639 onuLogger.WithFields(log.Fields{
640 "OnuId": o.ID,
641 "IntfId": o.PonPortID,
642 "OnuSn": o.Sn(),
643 }).Errorf("Cannot shutdown ONU: %s", err.Error())
644 return err
645 }
646
647 return nil
648}
649
650func (o *Onu) HandlePowerOnONU() error {
651 intitalState := o.InternalState.Current()
652
653 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800654 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
655 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800656 onuLogger.WithFields(log.Fields{
657 "OnuId": o.ID,
658 "IntfId": o.PonPortID,
659 "OnuSn": o.Sn(),
660 }).Errorf("Cannot poweron ONU: %s", err.Error())
661 return err
662 }
663 }
664
665 // turn off the LOS Alarm
666 losReq := pb.ONUAlarmRequest{
667 AlarmType: "ONU_ALARM_LOS",
668 SerialNumber: o.Sn(),
669 Status: "off",
670 }
671
672 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
673 onuLogger.WithFields(log.Fields{
674 "OnuId": o.ID,
675 "IntfId": o.PonPortID,
676 "OnuSn": o.Sn(),
677 }).Errorf("Cannot send LOS: %s", err.Error())
678 return err
679 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530680 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800681
682 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800683 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800684 onuLogger.WithFields(log.Fields{
685 "OnuId": o.ID,
686 "IntfId": o.PonPortID,
687 "OnuSn": o.Sn(),
688 }).Errorf("Cannot poweron ONU: %s", err.Error())
689 return err
690 }
691
692 // move o directly to enable state only when its a powercycle case
693 // in case of first time o poweron o will be moved to enable on
694 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800695 if intitalState == OnuStateDisabled {
696 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800697 onuLogger.WithFields(log.Fields{
698 "OnuId": o.ID,
699 "IntfId": o.PonPortID,
700 "OnuSn": o.Sn(),
701 }).Errorf("Cannot enable ONU: %s", err.Error())
702 return err
703 }
704 }
705
706 return nil
707}
708
709func (o *Onu) SetAlarm(alarmType string, status string) error {
710 alarmReq := pb.ONUAlarmRequest{
711 AlarmType: alarmType,
712 SerialNumber: o.Sn(),
713 Status: status,
714 }
715
716 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
717 if err != nil {
718 return err
719 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530720 raiseAlarm := false
721 if alarmReq.Status == "on" {
722 raiseAlarm = true
723 }
724 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800725 return nil
726}
727
728func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530729 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700730 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530731 if err != nil {
732 log.Errorf("error in getting msgType %v", err)
733 return
734 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800735 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530736 o.seqNumber = 0
737 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800738 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530739 o.seqNumber++
740 if o.seqNumber > 290 {
741 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
742 }
743 }
744 }
745}
746
Matteo Scandolof9d43412021-01-12 11:11:34 -0800747// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
748// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200749func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800750
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700751 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700752 "omciMsgType": msg.OmciMsg.MessageType,
753 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
754 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700755 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700756 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800757 }).Trace("omci-message-decoded")
758
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000759 if o.OmciMsgCounter < maxOmciMsgCounter {
760 o.OmciMsgCounter++
761 } else {
762 o.OmciMsgCounter = 1
763 }
764 if o.OmciMsgCounter > o.OmciResponseRate {
765 onuLogger.WithFields(log.Fields{
766 "OmciMsgCounter": o.OmciMsgCounter,
767 "OmciResponseRate": o.OmciResponseRate,
768 "omciMsgType": msg.OmciMsg.MessageType,
Matteo Scandoloa96e2242021-09-28 10:13:17 -0700769 "txId": msg.OmciMsg.TransactionID,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200770 }).Debug("skipping-omci-msg-response")
771 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000772 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800773 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800774 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700775 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800776 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800777 onuLogger.WithFields(log.Fields{
778 "IntfId": o.PonPortID,
779 "OnuId": o.ID,
780 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700781 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700782 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800783 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700784
785 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
786 o.PonPort.removeAllocId(o.SerialNumber)
787 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800788 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800789 case omci.MibUploadRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700790 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800791 case omci.MibUploadNextRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700792 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800793 case omci.GetRequestType:
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700794 onuDown := o.AdminLockState == 1
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700795 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId,
796 o.CommittedImageEntityId, o.StandbyImageVersion, o.ActiveImageVersion, o.CommittedImageVersion, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800797 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800798 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700799 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800800 switch msgObj.EntityClass {
801 case me.PhysicalPathTerminationPointEthernetUniClassID:
802 // if we're Setting a PPTP state
Matteo Scandolo8a574812021-05-20 15:18:53 -0700803 // we need to send the appropriate alarm (handled in the UNI struct)
804 uni, err := o.FindUniByEntityId(msgObj.EntityInstance)
805 if err != nil {
806 onuLogger.Error(err)
807 success = false
808 } else {
809 // 1 locks the UNI, 0 unlocks it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800810 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700811 var err error
Himani Chawla13b1ee02021-03-15 01:43:53 +0530812 if adminState == 1 {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700813 err = uni.Disable()
Girish Gowdra996d81e2021-04-21 16:16:27 -0700814 } else {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700815 err = uni.Enable()
Himani Chawla13b1ee02021-03-15 01:43:53 +0530816 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700817 if err != nil {
818 onuLogger.WithFields(log.Fields{
819 "IntfId": o.PonPortID,
820 "OnuId": o.ID,
821 "UniMeId": uni.MeId,
822 "UniId": uni.ID,
823 "SerialNumber": o.Sn(),
824 "Err": err.Error(),
825 }).Warn("cannot-change-uni-status")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800826 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800827 }
Girish Gowdra1ddcb202021-06-25 12:17:09 -0700828 case me.OnuGClassID:
829 o.AdminLockState = msgObj.Attributes["AdministrativeState"].(uint8)
830 onuLogger.WithFields(log.Fields{
831 "IntfId": o.PonPortID,
832 "OnuId": o.ID,
833 "SerialNumber": o.Sn(),
834 "AdminLockState": o.AdminLockState,
835 }).Debug("set-onu-admin-lock-state")
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800836 case me.TContClassID:
837 allocId := msgObj.Attributes["AllocId"].(uint16)
838
839 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
840 // otherwise we are adding it
841 if allocId == 255 || allocId == 65535 {
842 onuLogger.WithFields(log.Fields{
843 "IntfId": o.PonPortID,
844 "OnuId": o.ID,
845 "TContId": msgObj.EntityInstance,
846 "AllocId": allocId,
847 "SerialNumber": o.Sn(),
848 }).Trace("freeing-alloc-id-via-omci")
849 o.PonPort.removeAllocId(o.SerialNumber)
850 } else {
851 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
852 onuLogger.WithFields(log.Fields{
853 "IntfId": o.PonPortID,
854 "OnuId": o.ID,
855 "AllocId": allocId,
856 "SerialNumber": o.Sn(),
857 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
858 success = false
859 } else {
860 onuLogger.WithFields(log.Fields{
861 "IntfId": o.PonPortID,
862 "OnuId": o.ID,
863 "TContId": msgObj.EntityInstance,
864 "AllocId": allocId,
865 "SerialNumber": o.Sn(),
866 }).Trace("storing-alloc-id-via-omci")
867 o.PonPort.storeAllocId(allocId, o.SerialNumber)
868 }
869 }
870
871 }
872
873 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700874 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800875 o.MibDataSync++
876 }
877 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700878 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800879 }
880 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800881 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
882 var used bool
883 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700884 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800885 if err == nil {
886 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700887 // GemPort 4069 is reserved for multicast and shared across ONUs
888 if msgObj.EntityInstance != 4069 {
889 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
890 onuLogger.WithFields(log.Fields{
891 "IntfId": o.PonPortID,
892 "OnuId": o.ID,
893 "GemPortId": msgObj.EntityInstance,
894 "SerialNumber": o.Sn(),
895 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
896 } else {
897 onuLogger.WithFields(log.Fields{
898 "IntfId": o.PonPortID,
899 "OnuId": o.ID,
900 "GemPortId": msgObj.EntityInstance,
901 "SerialNumber": o.Sn(),
902 }).Trace("storing-gem-port-id-via-omci")
903 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
904 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800905 }
906 }
907 }
908
909 // if the gemPort is valid then increment the MDS and return a successful response
910 // otherwise fail the request
911 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
912 // validation this check will need to be rewritten
913 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700914 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800915 o.MibDataSync++
916 }
917 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700918 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800919 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800920 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700921 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800922 if err == nil {
923 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
924 onuLogger.WithFields(log.Fields{
925 "IntfId": o.PonPortID,
926 "OnuId": o.ID,
927 "GemPortId": msgObj.EntityInstance,
928 "SerialNumber": o.Sn(),
929 }).Trace("freeing-gem-port-id-via-omci")
930 o.PonPort.removeGemPort(msgObj.EntityInstance)
931 }
932 }
933
Matteo Scandolob5913142021-03-19 16:10:18 -0700934 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800935 o.MibDataSync++
936 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800937 case omci.RebootRequestType:
938
Matteo Scandolob5913142021-03-19 16:10:18 -0700939 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800940
941 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800942 // we run this in a separate goroutine so that
943 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800944 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800945 if err := o.Reboot(10 * time.Second); err != nil {
946 log.WithFields(log.Fields{
947 "IntfId": o.PonPortID,
948 "OnuId": o.ID,
949 "SerialNumber": o.Sn(),
950 "err": err,
951 }).Error("cannot-reboot-onu-after-omci-reboot-request")
952 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800953 }()
954 case omci.TestRequestType:
Girish Gowdra161d27a2021-05-05 12:01:44 -0700955 var classID me.ClassID
956 var omciResult me.Results
957 var instID uint16
958 responsePkt, errResp, classID, instID, omciResult = omcilib.CreateTestResponse(msg.OmciPkt, msg.OmciMsg)
959 // Send TestResult only in case the TestResponse omci result code is me.Success
960 if responsePkt != nil && errResp == nil && omciResult == me.Success {
961 if testResultPkt, err := omcilib.CreateTestResult(classID, instID, msg.OmciMsg.TransactionID); err == nil {
962 // send test results asynchronously
963 go func() {
964 // Send test results after a second to emulate async behavior
965 time.Sleep(1 * time.Second)
966 if testResultPkt != nil {
967 if err := o.sendOmciIndication(testResultPkt, msg.OmciMsg.TransactionID, stream); err != nil {
968 onuLogger.WithFields(log.Fields{
969 "IntfId": o.PonPortID,
970 "SerialNumber": o.Sn(),
971 "omciPacket": testResultPkt,
972 "msg.OmciMsgType": msg.OmciMsg.MessageType,
973 "transCorrId": msg.OmciMsg.TransactionID,
974 }).Errorf("failed-to-send-omci-message: %v", err)
975 }
976 }
977 }()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800978 }
979 }
Girish Gowdraa539f522021-02-15 23:00:45 -0800980 case omci.SynchronizeTimeRequestType:
981 // MDS counter increment is not required for this message type
Matteo Scandolob5913142021-03-19 16:10:18 -0700982 responsePkt, _ = omcilib.CreateSyncTimeResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -0800983 case omci.StartSoftwareDownloadRequestType:
984
985 o.ImageSoftwareReceivedSections = 0
Himani Chawla4ff5fab2021-11-09 19:19:29 +0530986 o.ImageSectionData = []byte{}
Matteo Scandolob5913142021-03-19 16:10:18 -0700987 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
Matteo Scandolocedde462021-03-09 17:37:16 -0800988
Matteo Scandolob5913142021-03-19 16:10:18 -0700989 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -0800990 o.MibDataSync++
991 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
992 onuLogger.WithFields(log.Fields{
993 "OnuId": o.ID,
994 "IntfId": o.PonPortID,
995 "OnuSn": o.Sn(),
996 "Err": err.Error(),
997 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
998 }
999 } else {
1000 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001001 "OmciMsgType": msg.OmciMsg.MessageType,
1002 "TransCorrId": msg.OmciMsg.TransactionID,
1003 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001004 "IntfId": o.PonPortID,
1005 "SerialNumber": o.Sn(),
1006 }).Error("error-while-processing-start-software-download-request")
1007 }
1008 case omci.DownloadSectionRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001009 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001010 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001011 "OmciMsgType": msg.OmciMsg.MessageType,
1012 "TransCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001013 "EntityInstance": msgObj.EntityInstance,
1014 "SectionNumber": msgObj.SectionNumber,
1015 "SectionData": msgObj.SectionData,
1016 }).Trace("received-download-section-request")
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001017 //Extracting the first 14 bytes to use as a version for this image.
1018 if o.ImageSoftwareReceivedSections == 0 {
1019 o.StandbyImageVersion = string(msgObj.SectionData[0:14])
1020 }
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301021 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
Matteo Scandolocedde462021-03-09 17:37:16 -08001022 o.ImageSoftwareReceivedSections++
1023 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1024 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1025 onuLogger.WithFields(log.Fields{
1026 "OnuId": o.ID,
1027 "IntfId": o.PonPortID,
1028 "OnuSn": o.Sn(),
1029 "Err": err.Error(),
1030 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1031 }
1032 }
1033 }
1034 case omci.DownloadSectionRequestWithResponseType:
1035 // NOTE we only need to respond if an ACK is requested
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301036 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001037 onuLogger.WithFields(log.Fields{
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301038 "OmciMsgType": msg.OmciMsg.MessageType,
1039 "TransCorrId": msg.OmciMsg.TransactionID,
1040 "EntityInstance": msgObj.EntityInstance,
1041 "SectionNumber": msgObj.SectionNumber,
1042 "SectionData": msgObj.SectionData,
1043 }).Trace("received-download-section-request-with-response-type")
1044 o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
1045 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1046
1047 if errResp != nil {
1048 onuLogger.WithFields(log.Fields{
1049 "OmciMsgType": msg.OmciMsg.MessageType,
1050 "TransCorrId": msg.OmciMsg.TransactionID,
1051 "Err": errResp.Error(),
1052 "IntfId": o.PonPortID,
1053 "SerialNumber": o.Sn(),
1054 }).Error("error-while-processing-create-download-section-response")
1055 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
1056 }
1057 o.ImageSoftwareReceivedSections++
Matteo Scandolocedde462021-03-09 17:37:16 -08001058 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001059 case omci.EndSoftwareDownloadRequestType:
1060
1061 // In the startSoftwareDownload we get the image size and the window size.
1062 // We calculate how many DownloadSection we should receive and validate
1063 // that we got the correct amount when we receive this message
1064 success := true
1065 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1066 onuLogger.WithFields(log.Fields{
1067 "OnuId": o.ID,
1068 "IntfId": o.PonPortID,
1069 "OnuSn": o.Sn(),
1070 "ExpectedSections": o.ImageSoftwareExpectedSections,
1071 "ReceivedSections": o.ImageSoftwareReceivedSections,
1072 }).Errorf("onu-did-not-receive-all-image-sections")
1073 success = false
1074 }
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301075 if success {
1076 // Validate Image Crc.
1077 msgObj, err := omcilib.ParseEndSoftwareDownloadRequest(msg.OmciPkt)
1078 if err != nil {
1079 onuLogger.WithFields(log.Fields{
1080 "OmciMsgType": msg.OmciMsg.MessageType,
1081 "TransCorrId": msg.OmciMsg.TransactionID,
1082 "Err": errResp.Error(),
1083 "IntfId": o.PonPortID,
1084 "SerialNumber": o.Sn(),
1085 }).Error("error-while-processing-end-software-download-request")
1086 }
1087 computedCRC := crc32a.Checksum(o.ImageSectionData[:int(msgObj.ImageSize)])
1088 //Convert the crc to network byte order
1089 var byteSlice []byte = make([]byte, 4)
1090 binary.LittleEndian.PutUint32(byteSlice, uint32(computedCRC))
1091 computedCRC = binary.BigEndian.Uint32(byteSlice)
Matteo Scandolocedde462021-03-09 17:37:16 -08001092
Himani Chawla4ff5fab2021-11-09 19:19:29 +05301093 onuLogger.WithFields(log.Fields{
1094 "OnuId": o.ID,
1095 "IntfId": o.PonPortID,
1096 "OnuSn": o.Sn(),
1097 "ReceivedCRC": msgObj.CRC32,
1098 "CalculatedCRC": computedCRC,
1099 }).Debug("onu-image-crc-validation-params")
1100
1101 if msgObj.CRC32 != computedCRC {
1102 onuLogger.WithFields(log.Fields{
1103 "OnuId": o.ID,
1104 "IntfId": o.PonPortID,
1105 "OnuSn": o.Sn(),
1106 "ReceivedCRC": msgObj.CRC32,
1107 "CalculatedCRC": computedCRC,
1108 }).Errorf("onu-image-crc-validation-falied")
1109 success = false
1110 }
1111 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001112 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001113 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001114 o.MibDataSync++
1115 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1116 onuLogger.WithFields(log.Fields{
1117 "OnuId": o.ID,
1118 "IntfId": o.PonPortID,
1119 "OnuSn": o.Sn(),
1120 "Err": err.Error(),
1121 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1122 }
1123 } else {
1124 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001125 "OmciMsgType": msg.OmciMsg.MessageType,
1126 "TransCorrId": msg.OmciMsg.TransactionID,
1127 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001128 "IntfId": o.PonPortID,
1129 "SerialNumber": o.Sn(),
1130 }).Error("error-while-processing-end-software-download-request")
1131 }
1132 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001133 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001134 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1135 onuLogger.WithFields(log.Fields{
1136 "OnuId": o.ID,
1137 "IntfId": o.PonPortID,
1138 "OnuSn": o.Sn(),
1139 "Err": err.Error(),
1140 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1141 }
1142 }
1143 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001144 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001145 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001146 o.MibDataSync++
1147 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1148 onuLogger.WithFields(log.Fields{
1149 "OnuId": o.ID,
1150 "IntfId": o.PonPortID,
1151 "OnuSn": o.Sn(),
1152 "Err": err.Error(),
1153 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1154 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001155 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001156 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001157 previousActiveImage := o.ActiveImageVersion
1158 o.ActiveImageVersion = o.StandbyImageVersion
1159 o.StandbyImageVersion = previousActiveImage
Matteo Scandolocedde462021-03-09 17:37:16 -08001160 } else {
1161 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1162 }
1163 onuLogger.WithFields(log.Fields{
1164 "OnuId": o.ID,
1165 "IntfId": o.PonPortID,
1166 "OnuSn": o.Sn(),
1167 "ActiveImageEntityId": o.ActiveImageEntityId,
1168 "CommittedImageEntityId": o.CommittedImageEntityId,
1169 }).Info("onu-software-image-activated")
1170
1171 // powercycle the ONU
1172 // we run this in a separate goroutine so that
1173 // the ActivateSoftwareResponse is sent to VOLTHA
1174 // NOTE do we need to wait before rebooting?
1175 go func() {
1176 if err := o.Reboot(10 * time.Second); err != nil {
1177 log.WithFields(log.Fields{
1178 "IntfId": o.PonPortID,
1179 "OnuId": o.ID,
1180 "SerialNumber": o.Sn(),
1181 "err": err,
1182 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1183 }
1184 }()
1185 }
1186 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001187 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001188 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001189 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001190 // TODO validate that the image to commit is:
1191 // - active
1192 // - not already committed
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001193 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandolocedde462021-03-09 17:37:16 -08001194 o.CommittedImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001195 //committed becomes standby
1196 o.StandbyImageVersion = o.CommittedImageVersion
1197 o.CommittedImageVersion = o.ActiveImageVersion
Matteo Scandolocedde462021-03-09 17:37:16 -08001198 } else {
1199 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1200 }
1201 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1202 onuLogger.WithFields(log.Fields{
1203 "OnuId": o.ID,
1204 "IntfId": o.PonPortID,
1205 "OnuSn": o.Sn(),
1206 "Err": err.Error(),
1207 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1208 }
1209 onuLogger.WithFields(log.Fields{
1210 "OnuId": o.ID,
1211 "IntfId": o.PonPortID,
1212 "OnuSn": o.Sn(),
1213 "ActiveImageEntityId": o.ActiveImageEntityId,
1214 "CommittedImageEntityId": o.CommittedImageEntityId,
1215 }).Info("onu-software-image-committed")
1216 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301217 case omci.GetAllAlarmsRequestType:
1218 // Reset the alarm sequence number on receiving get all alarms request.
1219 o.onuAlarmsInfoLock.Lock()
1220 for key, alarmInfo := range o.onuAlarmsInfo {
1221 // reset the alarm sequence no
1222 alarmInfo.SequenceNo = 0
1223 o.onuAlarmsInfo[key] = alarmInfo
1224 }
1225 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001226 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301227 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001228 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301229 responsePkt = nil //Do not send any response for error case
1230 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001231 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001232 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001233 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1234 "omciPkt": msg.OmciPkt,
1235 "omciMsgType": msg.OmciMsg.MessageType,
1236 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001237 "IntfId": o.PonPortID,
1238 "SerialNumber": o.Sn(),
1239 }).Warnf("OMCI-message-not-supported")
1240 }
1241
1242 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001243 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001244 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001245 "IntfId": o.PonPortID,
1246 "SerialNumber": o.Sn(),
1247 "omciPacket": responsePkt,
1248 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1249 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001250 }).Errorf("failed-to-send-omci-message: %v", err)
1251 }
1252 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001253
Pragya Arya324337e2020-02-20 14:35:08 +05301254 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001255 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001256}
Pragya Arya324337e2020-02-20 14:35:08 +05301257
Matteo Scandolof9d43412021-01-12 11:11:34 -08001258// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1259func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1260 indication := &openolt.Indication_OmciInd{
1261 OmciInd: &openolt.OmciIndication{
1262 IntfId: o.PonPortID,
1263 OnuId: o.ID,
1264 Pkt: responsePkt,
1265 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001266 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001267 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1268 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001269 }
1270 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001271 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001272 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001273 "omciPacket": indication.OmciInd.Pkt,
1274 "transCorrId": txId,
1275 }).Trace("omci-message-sent")
1276 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001277}
1278
Matteo Scandolo8a574812021-05-20 15:18:53 -07001279// FindUniById retrieves a UNI by ID
1280func (o *Onu) FindUniById(uniID uint32) (*UniPort, error) {
1281 for _, u := range o.UniPorts {
1282 uni := u.(*UniPort)
1283 if uni.ID == uniID {
1284 return uni, nil
1285 }
Matteo Scandolo27428702019-10-11 16:21:16 -07001286 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001287 return nil, fmt.Errorf("cannot-find-uni-with-id-%d-on-onu-%s", uniID, o.Sn())
1288}
1289
1290// FindUniByEntityId retrieves a uni by MeID (the OMCI entity ID)
1291func (o *Onu) FindUniByEntityId(meId uint16) (*UniPort, error) {
1292 entityId := omcilib.EntityID{}.FromUint16(meId)
1293 for _, u := range o.UniPorts {
1294 uni := u.(*UniPort)
1295 if uni.MeId.Equals(entityId) {
1296 return uni, nil
1297 }
1298 }
1299 return nil, fmt.Errorf("cannot-find-uni-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
Matteo Scandolo27428702019-10-11 16:21:16 -07001300}
1301
William Kurkian0418bc82019-11-06 12:16:24 -05001302func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001303 onuLogger.WithFields(log.Fields{
1304 "IntfId": o.PonPortID,
1305 "OnuId": id,
1306 "SerialNumber": o.Sn(),
1307 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001308 o.ID = id
1309}
1310
Matteo Scandolof9d43412021-01-12 11:11:34 -08001311func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001312 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001313 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001314 "Cookie": msg.Flow.Cookie,
1315 "DstPort": msg.Flow.Classifier.DstPort,
1316 "FlowId": msg.Flow.FlowId,
1317 "FlowType": msg.Flow.FlowType,
1318 "GemportId": msg.Flow.GemportId,
1319 "InnerVlan": msg.Flow.Classifier.IVid,
1320 "IntfId": msg.Flow.AccessIntfId,
1321 "IpProto": msg.Flow.Classifier.IpProto,
1322 "OnuId": msg.Flow.OnuId,
1323 "OnuSn": o.Sn(),
1324 "OuterVlan": msg.Flow.Classifier.OVid,
1325 "PortNo": msg.Flow.PortNo,
1326 "SrcPort": msg.Flow.Classifier.SrcPort,
1327 "UniID": msg.Flow.UniId,
1328 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1329 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1330 "ClassifierIVid": msg.Flow.Classifier.IVid,
1331 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001332 "ReplicateFlow": msg.Flow.ReplicateFlow,
1333 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001334 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001335
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001336 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001337
1338 var gemPortId uint32
1339 if msg.Flow.ReplicateFlow {
1340 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1341 // first available gemport (we only need to send one packet)
1342 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1343 gemPortId = msg.Flow.PbitToGemport[0]
1344 } else {
1345 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1346 gemPortId = uint32(msg.Flow.GemportId)
1347 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001348
1349 uni, err := o.FindUniById(uint32(msg.Flow.UniId))
1350 if err != nil {
1351 onuLogger.WithFields(log.Fields{
1352 "IntfId": o.PonPortID,
1353 "OnuId": o.ID,
1354 "UniId": msg.Flow.UniId,
1355 "PortNo": msg.Flow.PortNo,
1356 "SerialNumber": o.Sn(),
1357 "FlowId": msg.Flow.FlowId,
1358 "FlowType": msg.Flow.FlowType,
1359 }).Error("cannot-find-uni-port-for-flow")
1360 }
1361
1362 uni.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
1363 uni.StorePortNo(msg.Flow.PortNo)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001364
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001365 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001366 uni.HandleAuth()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001367 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1368 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001369 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001370 uni.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001371 }
1372}
1373
Matteo Scandolof9d43412021-01-12 11:11:34 -08001374func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001375 onuLogger.WithFields(log.Fields{
1376 "IntfId": o.PonPortID,
1377 "OnuId": o.ID,
1378 "SerialNumber": o.Sn(),
1379 "FlowId": msg.Flow.FlowId,
1380 "FlowType": msg.Flow.FlowType,
1381 }).Debug("ONU receives FlowRemove")
1382
1383 for idx, flow := range o.FlowIds {
1384 // If the gemport is found, delete it from local cache.
1385 if flow == msg.Flow.FlowId {
1386 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1387 break
1388 }
1389 }
1390
1391 if len(o.FlowIds) == 0 {
1392 onuLogger.WithFields(log.Fields{
1393 "IntfId": o.PonPortID,
1394 "OnuId": o.ID,
1395 "SerialNumber": o.Sn(),
1396 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001397
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301398 // check if ONU delete is performed and
1399 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001400 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301401 close(o.Channel)
1402 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001403 }
1404}
1405
Matteo Scandolocedde462021-03-09 17:37:16 -08001406func (o *Onu) Reboot(timeout time.Duration) error {
1407 onuLogger.WithFields(log.Fields{
1408 "IntfId": o.PonPortID,
1409 "OnuId": o.ID,
1410 "SerialNumber": o.Sn(),
1411 }).Debug("shutting-down-onu")
1412 if err := o.HandleShutdownONU(); err != nil {
1413 return err
1414 }
1415 time.Sleep(timeout)
1416 onuLogger.WithFields(log.Fields{
1417 "IntfId": o.PonPortID,
1418 "OnuId": o.ID,
1419 "SerialNumber": o.Sn(),
1420 }).Debug("power-on-onu")
1421 if err := o.HandlePowerOnONU(); err != nil {
1422 return err
1423 }
1424 return nil
1425}
1426
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001427// BBR methods
1428
1429func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1430 omciMsg := openolt.OmciMsg{
1431 IntfId: intfId,
1432 OnuId: onuId,
1433 Pkt: pktBytes,
1434 }
1435
1436 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1437 log.WithFields(log.Fields{
1438 "IntfId": intfId,
1439 "OnuId": onuId,
1440 "SerialNumber": common.OnuSnToString(sn),
1441 "Pkt": omciMsg.Pkt,
1442 }).Fatalf("Failed to send MIB Reset")
1443 }
1444 log.WithFields(log.Fields{
1445 "IntfId": intfId,
1446 "OnuId": onuId,
1447 "SerialNumber": common.OnuSnToString(sn),
1448 "Pkt": omciMsg.Pkt,
1449 }).Tracef("Sent OMCI message %s", msgType)
1450}
1451
1452func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1453 var next uint16
1454 if len(highPriority) > 0 && highPriority[0] {
1455 next = onu.hpTid
1456 onu.hpTid += 1
1457 if onu.hpTid < 0x8000 {
1458 onu.hpTid = 0x8000
1459 }
1460 } else {
1461 next = onu.tid
1462 onu.tid += 1
1463 if onu.tid >= 0x8000 {
1464 onu.tid = 1
1465 }
1466 }
1467 return next
1468}
1469
1470// TODO move this method in responders/omcisim
Matteo Scandolo8a574812021-05-20 15:18:53 -07001471// StartOmci is called in BBR to start the OMCI state machine
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001472func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1473 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1474 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1475}
1476
Matteo Scandolof9d43412021-01-12 11:11:34 -08001477// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1478func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1479
1480 // we need to encode the packet in HEX
1481 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1482 hex.Encode(pkt, msg.OmciInd.Pkt)
1483 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1484 if err != nil {
1485 log.WithFields(log.Fields{
1486 "IntfId": o.PonPortID,
1487 "SerialNumber": o.Sn(),
1488 "omciPacket": msg.OmciInd.Pkt,
1489 }).Error("BBR Cannot parse OMCI packet")
1490 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001491
1492 log.WithFields(log.Fields{
1493 "IntfId": msg.OmciInd.IntfId,
1494 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001495 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001496 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001497 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301498 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001499 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001500 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001501 log.WithFields(log.Fields{
1502 "IntfId": msg.OmciInd.IntfId,
1503 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001504 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001505 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001506 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001507 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001508 case omci.MibResetResponseType:
1509 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1510 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1511 case omci.MibUploadResponseType:
1512 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1513 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1514 case omci.MibUploadNextResponseType:
1515 o.seqNumber++
Matteo Scandolo8a574812021-05-20 15:18:53 -07001516 // once the mibUpload is complete send a SetRequest for the PPTP to enable the UNI
1517 // NOTE that in BBR we only enable the first UNI
1518 if o.seqNumber == o.MibDb.NumberOfCommands {
1519 meId := omcilib.GenerateUniPortEntityId(1)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001520
Matteo Scandolo8a574812021-05-20 15:18:53 -07001521 meParams := me.ParamData{
1522 EntityID: meId.ToUint16(),
1523 Attributes: me.AttributeValueMap{"AdministrativeState": 0},
1524 }
1525 managedEntity, omciError := me.NewPhysicalPathTerminationPointEthernetUni(meParams)
1526 if omciError.GetError() != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001527 onuLogger.WithFields(log.Fields{
1528 "OnuId": o.ID,
1529 "IntfId": o.PonPortID,
1530 "OnuSn": o.Sn(),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001531 }).Fatal(omciError.GetError())
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001532 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001533
1534 setPPtp, _ := omcilib.CreateSetRequest(managedEntity, 1)
1535 sendOmciMsg(setPPtp, o.PonPortID, o.ID, o.SerialNumber, "setRquest", client)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001536 } else {
1537 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1538 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001539 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001540 case omci.SetResponseType:
1541 // once we set the PPTP to active we can start sending flows
1542
1543 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
1544 onuLogger.WithFields(log.Fields{
1545 "OnuId": o.ID,
1546 "IntfId": o.PonPortID,
1547 "OnuSn": o.Sn(),
1548 }).Errorf("Error while transitioning ONU State %v", err)
1549 }
1550 case omci.AlarmNotificationType:
1551 log.Info("bbr-received-alarm")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001552 }
1553}
1554
1555func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1556
1557 classifierProto := openolt.Classifier{
1558 EthType: uint32(layers.EthernetTypeEAPOL),
1559 OVid: 4091,
1560 }
1561
1562 actionProto := openolt.Action{}
1563
1564 downstreamFlow := openolt.Flow{
1565 AccessIntfId: int32(o.PonPortID),
1566 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001567 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001568 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001569 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001570 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001571 Classifier: &classifierProto,
1572 Action: &actionProto,
1573 Priority: int32(100),
1574 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001575 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1576 // AllocId and GemPorts need to be unique per PON
1577 // for now use the ONU-ID, will need to change once we support multiple UNIs
1578 AllocId: int32(o.ID),
1579 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001580 }
1581
1582 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1583 log.WithFields(log.Fields{
1584 "IntfId": o.PonPortID,
1585 "OnuId": o.ID,
1586 "FlowId": downstreamFlow.FlowId,
1587 "PortNo": downstreamFlow.PortNo,
1588 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001589 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001590 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001591 }
1592 log.WithFields(log.Fields{
1593 "IntfId": o.PonPortID,
1594 "OnuId": o.ID,
1595 "FlowId": downstreamFlow.FlowId,
1596 "PortNo": downstreamFlow.PortNo,
1597 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1598 }).Info("Sent EAPOL Flow")
1599}
1600
1601func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001602
Matteo Scandolo8a574812021-05-20 15:18:53 -07001603 // BBR only works with a single UNI and a single service (ATT HSIA)
1604 hsia := o.UniPorts[0].(*UniPort).Services[0].(*Service)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001605 classifierProto := openolt.Classifier{
1606 EthType: uint32(layers.EthernetTypeIPv4),
1607 SrcPort: uint32(68),
1608 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001609 OVid: uint32(hsia.CTag),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001610 OPbits: 255,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001611 }
1612
1613 actionProto := openolt.Action{}
1614
1615 downstreamFlow := openolt.Flow{
1616 AccessIntfId: int32(o.PonPortID),
1617 OnuId: int32(o.ID),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001618 UniId: int32(0), // BBR only supports a single UNI
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001619 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001620 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001621 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001622 Classifier: &classifierProto,
1623 Action: &actionProto,
1624 Priority: int32(100),
1625 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001626 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1627 // AllocId and GemPorts need to be unique per PON
1628 // for now use the ONU-ID, will need to change once we support multiple UNIs
1629 AllocId: int32(o.ID),
1630 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001631 }
1632
1633 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1634 log.WithFields(log.Fields{
1635 "IntfId": o.PonPortID,
1636 "OnuId": o.ID,
1637 "FlowId": downstreamFlow.FlowId,
1638 "PortNo": downstreamFlow.PortNo,
1639 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001640 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001641 }).Fatalf("Failed to send DHCP Flow")
1642 }
1643 log.WithFields(log.Fields{
1644 "IntfId": o.PonPortID,
1645 "OnuId": o.ID,
1646 "FlowId": downstreamFlow.FlowId,
1647 "PortNo": downstreamFlow.PortNo,
1648 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1649 }).Info("Sent DHCP Flow")
1650}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301651
1652// DeleteFlow method search and delete flowKey from the onu flows slice
1653func (onu *Onu) DeleteFlow(key FlowKey) {
1654 for pos, flowKey := range onu.Flows {
1655 if flowKey == key {
1656 // delete the flowKey by shifting all flowKeys by one
1657 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1658 t := make([]FlowKey, len(onu.Flows))
1659 copy(t, onu.Flows)
1660 onu.Flows = t
1661 break
1662 }
1663 }
1664}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301665
1666func (onu *Onu) ReDiscoverOnu() {
1667 // Wait for few seconds to be sure of the cleanup
1668 time.Sleep(5 * time.Second)
1669
1670 onuLogger.WithFields(log.Fields{
1671 "IntfId": onu.PonPortID,
1672 "OnuId": onu.ID,
1673 "OnuSn": onu.Sn(),
1674 }).Debug("Send ONU Re-Discovery")
1675
1676 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001677 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301678 log.WithFields(log.Fields{
1679 "IntfId": onu.PonPortID,
1680 "OnuSn": onu.Sn(),
1681 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001682 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301683 }
1684
Matteo Scandolocedde462021-03-09 17:37:16 -08001685 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301686 log.WithFields(log.Fields{
1687 "IntfId": onu.PonPortID,
1688 "OnuSn": onu.Sn(),
1689 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001690 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301691 }
1692}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001693
Matteo Scandolo8a574812021-05-20 15:18:53 -07001694// deprecated, delegate this to the uniPort
Matteo Scandolo4a036262020-08-17 15:56:13 -07001695func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001696 // FIXME is there a better way to avoid this loop?
1697 for _, u := range onu.UniPorts {
1698 uni := u.(*UniPort)
1699 for _, s := range uni.Services {
1700 service := s.(*Service)
1701 if service.HwAddress.String() == macAddress.String() {
1702 return service, nil
1703 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001704 }
1705 }
1706 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1707}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301708
Matteo Scandolo8a574812021-05-20 15:18:53 -07001709func (onu *Onu) findUniByPortNo(portNo uint32) (*UniPort, error) {
1710 for _, u := range onu.UniPorts {
1711 uni := u.(*UniPort)
1712 if uni.PortNo == portNo {
1713 return uni, nil
1714 }
1715 }
1716 return nil, fmt.Errorf("cannot-find-uni-with-port-no-%d", portNo)
1717}
1718
Himani Chawla13b1ee02021-03-15 01:43:53 +05301719func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1720 switch alarmType {
1721 case "ONU_ALARM_LOS":
1722 msg := bbsim.Message{
1723 Type: bbsim.UniStatusAlarm,
1724 Data: bbsim.UniStatusAlarmMessage{
1725 OnuSN: o.SerialNumber,
1726 OnuID: o.ID,
1727 EntityID: 257,
1728 RaiseOMCIAlarm: raiseOMCIAlarm,
1729 },
1730 }
1731 o.Channel <- msg
1732 }
1733
1734}
1735
1736func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1737 o.onuAlarmsInfoLock.Lock()
1738 defer o.onuAlarmsInfoLock.Unlock()
1739 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1740 if alarmInfo.SequenceNo == 255 {
1741 alarmInfo.SequenceNo = 1
1742 } else {
1743 alarmInfo.SequenceNo++
1744 }
1745 o.onuAlarmsInfo[key] = alarmInfo
1746 return alarmInfo.SequenceNo
1747 } else {
1748 // This is the first time alarm notification message is being sent
1749 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1750 SequenceNo: 1,
1751 }
1752 return 1
1753 }
1754}