blob: ab7c35f508ae9fe072cb76f0061145e5f59cc9aa [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"
Matteo Scandolo618a6582020-09-09 12:21:29 -070021 "encoding/hex"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070022 "fmt"
Matteo Scandolof9d43412021-01-12 11:11:34 -080023 pb "github.com/opencord/bbsim/api/bbsim"
24 "github.com/opencord/bbsim/internal/bbsim/alarmsim"
Matteo Scandolo4a036262020-08-17 15:56:13 -070025 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
26 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
27 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080028 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
29 me "github.com/opencord/omci-lib-go/generated"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010030 "net"
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080031 "strconv"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010032 "time"
33
Matteo Scandolo3bc73742019-08-20 14:04:04 -070034 "github.com/google/gopacket/layers"
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070035 "github.com/jpillora/backoff"
Matteo Scandolo4747d292019-08-05 11:50:18 -070036 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070037 "github.com/opencord/bbsim/internal/common"
38 omcilib "github.com/opencord/bbsim/internal/common/omci"
Matteo Scandolof9d43412021-01-12 11:11:34 -080039 "github.com/opencord/omci-lib-go"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070040 "github.com/opencord/voltha-protos/v4/go/openolt"
41 "github.com/opencord/voltha-protos/v4/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070042 log "github.com/sirupsen/logrus"
43)
44
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070045var onuLogger = log.WithFields(log.Fields{
46 "module": "ONU",
47})
48
Matteo Scandolocedde462021-03-09 17:37:16 -080049const (
50 // ONU transitions
51 OnuTxInitialize = "initialize"
52 OnuTxDiscover = "discover"
53 OnuTxEnable = "enable"
54 OnuTxDisable = "disable"
55 OnuTxPonDisable = "pon_disable"
56 OnuTxStartImageDownload = "start_image_download"
57 OnuTxProgressImageDownload = "progress_image_download"
58 OnuTxCompleteImageDownload = "complete_image_download"
59 OnuTxFailImageDownload = "fail_image_download"
60 OnuTxActivateImage = "activate_image"
61 OnuTxCommitImage = "commit_image"
62
63 // ONU States
64 OnuStateCreated = "created"
65 OnuStateInitialized = "initialized"
66 OnuStateDiscovered = "discovered"
67 OnuStateEnabled = "enabled"
68 OnuStateDisabled = "disabled"
69 OnuStatePonDisabled = "pon_disabled"
70 OnuStateImageDownloadStarted = "image_download_started"
71 OnuStateImageDownloadInProgress = "image_download_in_progress"
72 OnuStateImageDownloadComplete = "image_download_completed"
73 OnuStateImageDownloadError = "image_download_error"
74 OnuStateImageActivated = "software_image_activated"
75 OnuStateImageCommitted = "software_image_committed"
76
77 // BBR ONU States and Transitions
78 BbrOnuTxSendEapolFlow = "send_eapol_flow"
79 BbrOnuStateEapolFlowSent = "eapol_flow_sent"
80 BbrOnuTxSendDhcpFlow = "send_dhcp_flow"
81 BbrOnuStateDhcpFlowSent = "dhcp_flow_sent"
82)
83
Pragya Arya8bdb4532020-03-02 17:08:09 +053084type FlowKey struct {
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070085 ID uint64
Pragya Arya8bdb4532020-03-02 17:08:09 +053086 Direction string
87}
88
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070089type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -080090 ID uint32
91 PonPortID uint32
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070092 PonPort *PonPort
Matteo Scandoloe811ae92019-12-10 17:50:14 -080093 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +053094 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
95 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandolo4a036262020-08-17 15:56:13 -070096
97 Services []ServiceIf
98
99 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800100 // ONU State
Matteo Scandolo27428702019-10-11 16:21:16 -0700101 // PortNo comes with flows and it's used when sending packetIndications,
102 // There is one PortNo per UNI Port, for now we're only storing the first one
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700103 // FIXME add support for multiple UNIs (each UNI has a different PortNo)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800104 PortNo uint32
105 Flows []FlowKey
106 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700107
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700108 OperState *fsm.FSM
109 SerialNumber *openolt.SerialNumber
110
Matteo Scandolof9d43412021-01-12 11:11:34 -0800111 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700112
113 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800114 MibDataSync uint8
115 ImageSoftwareExpectedSections int
116 ImageSoftwareReceivedSections int
117 ActiveImageEntityId uint16
118 CommittedImageEntityId uint16
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800119
120 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700121 tid uint16
122 hpTid uint16
123 seqNumber uint16
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700124
Anand S Katti09541352020-01-29 15:54:01 +0530125 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
126 TrafficSchedulers *tech_profile.TrafficSchedulers
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700127}
128
Matteo Scandolo99f18462019-10-28 14:14:28 -0700129func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700130 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700131}
132
Matteo Scandolo4a036262020-08-17 15:56:13 -0700133func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, isMock bool) *Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700134
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700135 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800136 ID: id,
137 PonPortID: pon.ID,
138 PonPort: pon,
139 PortNo: 0,
140 tid: 0x1,
141 hpTid: 0x8000,
142 seqNumber: 0,
143 DoneChannel: make(chan bool, 1),
144 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
145 Flows: []FlowKey{},
146 DiscoveryDelay: delay,
147 MibDataSync: 0,
148 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
149 ImageSoftwareReceivedSections: 0,
150 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
151 CommittedImageEntityId: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700152 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800153 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700154 // NOTE this state machine is used to track the operational
155 // state as requested by VOLTHA
156 o.OperState = getOperStateFSM(func(e *fsm.Event) {
157 onuLogger.WithFields(log.Fields{
158 "ID": o.ID,
159 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
160 })
161
162 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
163 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800164 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700165 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700166 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800167 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
168 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
169 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100170 // 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 -0800171 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530172 // ONU state when PON port is disabled but ONU is power ON(more states should be added in src?)
Matteo Scandolocedde462021-03-09 17:37:16 -0800173 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStatePonDisabled},
174 // Software Image Download related states
175 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError}, Dst: OnuStateImageDownloadStarted},
176 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
177 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
178 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
179 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
180 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700181 // BBR States
182 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800183 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
184 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700185 },
186 fsm.Callbacks{
187 "enter_state": func(e *fsm.Event) {
188 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700189 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100190 "enter_initialized": func(e *fsm.Event) {
191 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800192 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800193
Matteo Scandolocedde462021-03-09 17:37:16 -0800194 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800195 onuLogger.WithFields(log.Fields{
196 "OnuId": o.ID,
197 "IntfId": o.PonPortID,
198 "OnuSn": o.Sn(),
199 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
200 }
201
Pragya Arya1cbefa42020-01-13 12:15:29 +0530202 if !isMock {
203 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700204 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530205 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100206 },
207 "enter_discovered": func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800208 msg := bbsim.Message{
209 Type: bbsim.OnuDiscIndication,
210 Data: bbsim.OnuDiscIndicationMessage{
211 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100212 },
213 }
214 o.Channel <- msg
215 },
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700216 "enter_enabled": func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800217
218 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
219 onuLogger.WithFields(log.Fields{
220 "IntfId": o.PonPortID,
221 "OnuId": o.ID,
222 "SerialNumber": o.Sn(),
223 }).Errorf("received-omci-with-sn-%s", common.OnuSnToString(sn))
224 return
225 } else {
226 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
227 }
228
Matteo Scandolof9d43412021-01-12 11:11:34 -0800229 msg := bbsim.Message{
230 Type: bbsim.OnuIndication,
231 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700232 OnuSN: o.SerialNumber,
233 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800234 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700235 },
236 }
237 o.Channel <- msg
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700238
239 // Once the ONU is enabled start listening for packets
240 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700241 s.Initialize(o.PonPort.Olt.OpenoltStream)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700242 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700243 },
244 "enter_disabled": func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700245
246 // clean the ONU state
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700247 o.PortNo = 0
248 o.Flows = []FlowKey{}
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800249 o.PonPort.removeOnuId(o.ID)
250 o.PonPort.removeAllocId(o.SerialNumber)
251 o.PonPort.removeGemPortBySn(o.SerialNumber)
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700252
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700253 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800254 if err := o.OperState.Event("disable"); err != nil {
255 onuLogger.WithFields(log.Fields{
256 "OnuId": o.ID,
257 "IntfId": o.PonPortID,
258 "OnuSn": o.Sn(),
259 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
260 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700261
262 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800263 msg := bbsim.Message{
264 Type: bbsim.OnuIndication,
265 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700266 OnuSN: o.SerialNumber,
267 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800268 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700269 },
270 }
271 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530272
273 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100274 // terminate the ONU's ProcessOnuMessages Go routine
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530275 if len(o.FlowIds) == 0 {
276 close(o.Channel)
277 }
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700278
279 for _, s := range o.Services {
280 s.Disable()
281 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700282 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700283 // BBR states
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700284 "enter_eapol_flow_sent": func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800285 msg := bbsim.Message{
286 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700287 }
288 o.Channel <- msg
289 },
290 "enter_dhcp_flow_sent": func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800291 msg := bbsim.Message{
292 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700293 }
294 o.Channel <- msg
295 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700296 },
297 )
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100298
Matteo Scandolo27428702019-10-11 16:21:16 -0700299 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700300}
301
William Kurkian0418bc82019-11-06 12:16:24 -0500302func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700303 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700304 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700305 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700306 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700307 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
308}
309
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100310// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000311func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700312 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100313 "onuID": o.ID,
314 "onuSN": o.Sn(),
315 "ponPort": o.PonPortID,
316 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700317
David Bainbridge103cf022019-12-16 20:11:35 +0000318loop:
319 for {
320 select {
321 case <-ctx.Done():
322 onuLogger.WithFields(log.Fields{
323 "onuID": o.ID,
324 "onuSN": o.Sn(),
325 }).Tracef("ONU message handling canceled via context")
326 break loop
327 case message, ok := <-o.Channel:
328 if !ok || ctx.Err() != nil {
329 onuLogger.WithFields(log.Fields{
330 "onuID": o.ID,
331 "onuSN": o.Sn(),
332 }).Tracef("ONU message handling canceled via channel close")
333 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700334 }
David Bainbridge103cf022019-12-16 20:11:35 +0000335 onuLogger.WithFields(log.Fields{
336 "onuID": o.ID,
337 "onuSN": o.Sn(),
338 "messageType": message.Type,
339 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700340
David Bainbridge103cf022019-12-16 20:11:35 +0000341 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800342 case bbsim.OnuDiscIndication:
343 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000344 // 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 +0530345 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000346 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800347 case bbsim.OnuIndication:
348 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000349 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800350 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800351 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800352 msg, _ := message.Data.(bbsim.OmciMessage)
353 o.handleOmciRequest(msg, stream)
354 case bbsim.UniStatusAlarm:
355 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
356 pkt := omcilib.CreateUniStatusAlarm(msg.AdminState, msg.EntityID)
357 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
358 onuLogger.WithFields(log.Fields{
359 "IntfId": o.PonPortID,
360 "SerialNumber": o.Sn(),
361 "omciPacket": pkt,
362 "adminState": msg.AdminState,
363 "entityID": msg.EntityID,
364 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
365 }
366 onuLogger.WithFields(log.Fields{
367 "IntfId": o.PonPortID,
368 "SerialNumber": o.Sn(),
369 "omciPacket": pkt,
370 "adminState": msg.AdminState,
371 "entityID": msg.EntityID,
372 }).Trace("UNI-Link-alarm-sent")
373 case bbsim.FlowAdd:
374 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700375 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800376 case bbsim.FlowRemoved:
377 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700378 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800379 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700380
Matteo Scandolof9d43412021-01-12 11:11:34 -0800381 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000382
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700383 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000384 "IntfId": msg.IntfId,
385 "OnuId": msg.OnuId,
386 "pktType": msg.Type,
387 }).Trace("Received OnuPacketOut Message")
388
Matteo Scandolo618a6582020-09-09 12:21:29 -0700389 if msg.Type == packetHandlers.EAPOL || msg.Type == packetHandlers.DHCP {
390
391 service, err := o.findServiceByMacAddress(msg.MacAddress)
392 if err != nil {
393 onuLogger.WithFields(log.Fields{
394 "IntfId": msg.IntfId,
395 "OnuId": msg.OnuId,
396 "pktType": msg.Type,
397 "MacAddress": msg.MacAddress,
398 "Pkt": hex.EncodeToString(msg.Packet.Data()),
399 "OnuSn": o.Sn(),
400 }).Error("Cannot find Service associated with packet")
401 return
402 }
403 service.PacketCh <- msg
404 } else if msg.Type == packetHandlers.IGMP {
405 // if it's an IGMP packet we assume we have a single IGMP service
406 for _, s := range o.Services {
407 service := s.(*Service)
408
409 if service.NeedsIgmp {
410 service.PacketCh <- msg
411 }
412 }
David Bainbridge103cf022019-12-16 20:11:35 +0000413 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700414
Matteo Scandolof9d43412021-01-12 11:11:34 -0800415 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000416 // NOTE we only receive BBR packets here.
417 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
418 // 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 -0800419 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000420
421 log.WithFields(log.Fields{
422 "IntfId": msg.IntfId,
423 "OnuId": msg.OnuId,
424 "pktType": msg.Type,
425 }).Trace("Received OnuPacketIn Message")
426
427 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700428 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, msg.GemPortId, o.Sn(), o.PortNo, o.InternalState, msg.Packet, stream, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000429 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700430 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000431 }
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700432 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800433 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800434 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800435 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
436 o.handleOmciResponse(msg, client)
437 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000438 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800439 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000440 o.sendDhcpFlow(client)
441 default:
442 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700443 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700444 }
445 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100446 onuLogger.WithFields(log.Fields{
447 "onuID": o.ID,
448 "onuSN": o.Sn(),
449 }).Debug("Stopped handling ONU Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700450}
451
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800452func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700453
454 sn := new(openolt.SerialNumber)
455
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700456 //sn = new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700457 sn.VendorId = []byte("BBSM")
458 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
459
460 return sn
461}
462
Matteo Scandolof9d43412021-01-12 11:11:34 -0800463func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700464 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800465 IntfId: o.PonPortID,
466 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700467 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700468
Matteo Scandolo4747d292019-08-05 11:50:18 -0700469 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700470 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700471 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700472 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700473
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700474 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800475 "IntfId": o.PonPortID,
476 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700477 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700478 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800479 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800480
481 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
482 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800483 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800484 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800485 o.sendOnuDiscIndication(msg, stream)
486 }
487 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700488}
489
Matteo Scandolof9d43412021-01-12 11:11:34 -0800490func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800491 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
492 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700493
494 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700495 IntfId: o.PonPortID,
496 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700497 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700498 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700499 SerialNumber: o.SerialNumber,
500 }}
501 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800502 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700503 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700504 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700505 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700506 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800507 "IntfId": o.PonPortID,
508 "OnuId": o.ID,
509 "VolthaOnuId": msg.OnuID,
510 "OperState": msg.OperState.String(),
511 "AdminState": msg.OperState.String(),
512 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700513 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700514
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700515}
516
Matteo Scandolof9d43412021-01-12 11:11:34 -0800517func (o *Onu) HandleShutdownONU() error {
518
519 dyingGasp := pb.ONUAlarmRequest{
520 AlarmType: "DYING_GASP",
521 SerialNumber: o.Sn(),
522 Status: "on",
523 }
524
525 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
526 onuLogger.WithFields(log.Fields{
527 "OnuId": o.ID,
528 "IntfId": o.PonPortID,
529 "OnuSn": o.Sn(),
530 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
531 return err
532 }
533
534 losReq := pb.ONUAlarmRequest{
535 AlarmType: "ONU_ALARM_LOS",
536 SerialNumber: o.Sn(),
537 Status: "on",
538 }
539
540 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
541 onuLogger.WithFields(log.Fields{
542 "OnuId": o.ID,
543 "IntfId": o.PonPortID,
544 "OnuSn": o.Sn(),
545 }).Errorf("Cannot send LOS: %s", err.Error())
546
547 return err
548 }
549
550 // TODO if it's the last ONU on the PON, then send a PON LOS
551
Matteo Scandolocedde462021-03-09 17:37:16 -0800552 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800553 onuLogger.WithFields(log.Fields{
554 "OnuId": o.ID,
555 "IntfId": o.PonPortID,
556 "OnuSn": o.Sn(),
557 }).Errorf("Cannot shutdown ONU: %s", err.Error())
558 return err
559 }
560
561 return nil
562}
563
564func (o *Onu) HandlePowerOnONU() error {
565 intitalState := o.InternalState.Current()
566
567 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800568 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
569 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800570 onuLogger.WithFields(log.Fields{
571 "OnuId": o.ID,
572 "IntfId": o.PonPortID,
573 "OnuSn": o.Sn(),
574 }).Errorf("Cannot poweron ONU: %s", err.Error())
575 return err
576 }
577 }
578
579 // turn off the LOS Alarm
580 losReq := pb.ONUAlarmRequest{
581 AlarmType: "ONU_ALARM_LOS",
582 SerialNumber: o.Sn(),
583 Status: "off",
584 }
585
586 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
587 onuLogger.WithFields(log.Fields{
588 "OnuId": o.ID,
589 "IntfId": o.PonPortID,
590 "OnuSn": o.Sn(),
591 }).Errorf("Cannot send LOS: %s", err.Error())
592 return err
593 }
594
595 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800596 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800597 onuLogger.WithFields(log.Fields{
598 "OnuId": o.ID,
599 "IntfId": o.PonPortID,
600 "OnuSn": o.Sn(),
601 }).Errorf("Cannot poweron ONU: %s", err.Error())
602 return err
603 }
604
605 // move o directly to enable state only when its a powercycle case
606 // in case of first time o poweron o will be moved to enable on
607 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800608 if intitalState == OnuStateDisabled {
609 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800610 onuLogger.WithFields(log.Fields{
611 "OnuId": o.ID,
612 "IntfId": o.PonPortID,
613 "OnuSn": o.Sn(),
614 }).Errorf("Cannot enable ONU: %s", err.Error())
615 return err
616 }
617 }
618
619 return nil
620}
621
622func (o *Onu) SetAlarm(alarmType string, status string) error {
623 alarmReq := pb.ONUAlarmRequest{
624 AlarmType: alarmType,
625 SerialNumber: o.Sn(),
626 Status: status,
627 }
628
629 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
630 if err != nil {
631 return err
632 }
633 return nil
634}
635
636func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530637 if olt.PublishEvents {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800638 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
Pragya Arya324337e2020-02-20 14:35:08 +0530639 if err != nil {
640 log.Errorf("error in getting msgType %v", err)
641 return
642 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800643 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530644 o.seqNumber = 0
645 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800646 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530647 o.seqNumber++
648 if o.seqNumber > 290 {
649 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
650 }
651 }
652 }
653}
654
Scott Bakerb90c4312020-03-12 21:33:25 -0700655// Create a TestResponse packet and send it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800656func (o *Onu) sendTestResult(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
657 resp, err := omcilib.BuildTestResult(msg.OmciMsg.Pkt)
Scott Bakerb90c4312020-03-12 21:33:25 -0700658 if err != nil {
659 return err
660 }
661
662 var omciInd openolt.OmciIndication
663 omciInd.IntfId = o.PonPortID
664 omciInd.OnuId = o.ID
665 omciInd.Pkt = resp
666
667 omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
668 if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
Scott Bakerb90c4312020-03-12 21:33:25 -0700669 return err
670 }
671 onuLogger.WithFields(log.Fields{
672 "IntfId": o.PonPortID,
673 "SerialNumber": o.Sn(),
674 "omciPacket": omciInd.Pkt,
675 }).Tracef("Sent TestResult OMCI message")
676
677 return nil
678}
679
Matteo Scandolof9d43412021-01-12 11:11:34 -0800680// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
681// and generate the appropriate response to it
682func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
683
684 omciPkt, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
685 if err != nil {
686 log.WithFields(log.Fields{
687 "IntfId": o.PonPortID,
688 "SerialNumber": o.Sn(),
Matteo Scandolocedde462021-03-09 17:37:16 -0800689 "omciPacket": omcilib.HexDecode(msg.OmciMsg.Pkt),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800690 }).Error("cannot-parse-OMCI-packet")
691 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700692
693 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800694 "omciMsgType": omciMsg.MessageType,
695 "transCorrId": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
696 "DeviceIdent": omciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700697 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700698 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800699 }).Trace("omci-message-decoded")
700
701 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800702 var errResp error
Matteo Scandolof9d43412021-01-12 11:11:34 -0800703 switch omciMsg.MessageType {
704 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800705 onuLogger.WithFields(log.Fields{
706 "IntfId": o.PonPortID,
707 "OnuId": o.ID,
708 "SerialNumber": o.Sn(),
709 }).Debug("received-mib-reset-request-resetting-mds")
Girish Gowdrae2683102021-03-05 08:24:26 -0800710 if responsePkt, errResp = omcilib.CreateMibResetResponse(omciMsg.TransactionID); errResp == nil {
711 o.MibDataSync = 0
712 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800713 case omci.MibUploadRequestType:
714 responsePkt, _ = omcilib.CreateMibUploadResponse(omciMsg.TransactionID)
715 case omci.MibUploadNextRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800716 responsePkt, _ = omcilib.CreateMibUploadNextResponse(omciPkt, omciMsg, o.MibDataSync)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800717 case omci.GetRequestType:
Matteo Scandolocedde462021-03-09 17:37:16 -0800718 responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId, o.CommittedImageEntityId)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800719 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800720 success := true
Matteo Scandolof9d43412021-01-12 11:11:34 -0800721 msgObj, _ := omcilib.ParseSetRequest(omciPkt)
722 switch msgObj.EntityClass {
723 case me.PhysicalPathTerminationPointEthernetUniClassID:
724 // if we're Setting a PPTP state
725 // we need to send the appropriate alarm
726
727 if msgObj.EntityInstance == 257 {
728 // for now we're only caring about the first UNI
729 // NOTE that the EntityID for the UNI port is for now hardcoded in
730 // omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
731 // are reported during the MIB Upload sequence
732 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
733 msg := bbsim.Message{
734 Type: bbsim.UniStatusAlarm,
735 Data: bbsim.UniStatusAlarmMessage{
736 OnuSN: o.SerialNumber,
737 OnuID: o.ID,
738 AdminState: adminState,
739 EntityID: msgObj.EntityInstance,
740 },
741 }
742 o.Channel <- msg
743 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800744 case me.TContClassID:
745 allocId := msgObj.Attributes["AllocId"].(uint16)
746
747 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
748 // otherwise we are adding it
749 if allocId == 255 || allocId == 65535 {
750 onuLogger.WithFields(log.Fields{
751 "IntfId": o.PonPortID,
752 "OnuId": o.ID,
753 "TContId": msgObj.EntityInstance,
754 "AllocId": allocId,
755 "SerialNumber": o.Sn(),
756 }).Trace("freeing-alloc-id-via-omci")
757 o.PonPort.removeAllocId(o.SerialNumber)
758 } else {
759 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
760 onuLogger.WithFields(log.Fields{
761 "IntfId": o.PonPortID,
762 "OnuId": o.ID,
763 "AllocId": allocId,
764 "SerialNumber": o.Sn(),
765 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
766 success = false
767 } else {
768 onuLogger.WithFields(log.Fields{
769 "IntfId": o.PonPortID,
770 "OnuId": o.ID,
771 "TContId": msgObj.EntityInstance,
772 "AllocId": allocId,
773 "SerialNumber": o.Sn(),
774 }).Trace("storing-alloc-id-via-omci")
775 o.PonPort.storeAllocId(allocId, o.SerialNumber)
776 }
777 }
778
779 }
780
781 if success {
782 if responsePkt, errResp = omcilib.CreateSetResponse(omciPkt, omciMsg, me.Success); errResp == nil {
783 o.MibDataSync++
784 }
785 } else {
786 responsePkt, _ = omcilib.CreateSetResponse(omciPkt, omciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800787 }
788 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800789 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
790 var used bool
791 var sn *openolt.SerialNumber
792 msgObj, err := omcilib.ParseCreateRequest(omciPkt)
793 if err == nil {
794 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
795 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
796 onuLogger.WithFields(log.Fields{
797 "IntfId": o.PonPortID,
798 "OnuId": o.ID,
799 "GemPortId": msgObj.EntityInstance,
800 "SerialNumber": o.Sn(),
801 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
802 } else {
803 onuLogger.WithFields(log.Fields{
804 "IntfId": o.PonPortID,
805 "OnuId": o.ID,
806 "GemPortId": msgObj.EntityInstance,
807 "SerialNumber": o.Sn(),
808 }).Trace("storing-gem-port-id-via-omci")
809 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
810 }
811 }
812 }
813
814 // if the gemPort is valid then increment the MDS and return a successful response
815 // otherwise fail the request
816 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
817 // validation this check will need to be rewritten
818 if !used {
819 if responsePkt, errResp = omcilib.CreateCreateResponse(omciPkt, omciMsg, me.Success); errResp == nil {
820 o.MibDataSync++
821 }
822 } else {
823 responsePkt, _ = omcilib.CreateCreateResponse(omciPkt, omciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800824 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800825 case omci.DeleteRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800826 msgObj, err := omcilib.ParseDeleteRequest(omciPkt)
827 if err == nil {
828 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
829 onuLogger.WithFields(log.Fields{
830 "IntfId": o.PonPortID,
831 "OnuId": o.ID,
832 "GemPortId": msgObj.EntityInstance,
833 "SerialNumber": o.Sn(),
834 }).Trace("freeing-gem-port-id-via-omci")
835 o.PonPort.removeGemPort(msgObj.EntityInstance)
836 }
837 }
838
Girish Gowdrae2683102021-03-05 08:24:26 -0800839 if responsePkt, errResp = omcilib.CreateDeleteResponse(omciPkt, omciMsg); errResp == nil {
840 o.MibDataSync++
841 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800842 case omci.RebootRequestType:
843
844 responsePkt, _ = omcilib.CreateRebootResponse(omciPkt, omciMsg)
845
846 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800847 // we run this in a separate goroutine so that
848 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800849 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800850 if err := o.Reboot(10 * time.Second); err != nil {
851 log.WithFields(log.Fields{
852 "IntfId": o.PonPortID,
853 "OnuId": o.ID,
854 "SerialNumber": o.Sn(),
855 "err": err,
856 }).Error("cannot-reboot-onu-after-omci-reboot-request")
857 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800858 }()
859 case omci.TestRequestType:
860
861 // Test message is special, it requires sending two packets:
862 // first packet: TestResponse, says whether test was started successully, handled by omci-sim
863 // second packet, TestResult, reports the result of running the self-test
864 // TestResult can come some time after a TestResponse
865 // TODO: Implement some delay between the TestResponse and the TestResult
866 isTest, err := omcilib.IsTestRequest(msg.OmciMsg.Pkt)
867 if (err == nil) && (isTest) {
868 if sendErr := o.sendTestResult(msg, stream); sendErr != nil {
869 onuLogger.WithFields(log.Fields{
870 "IntfId": o.PonPortID,
Matteo Scandolocedde462021-03-09 17:37:16 -0800871 "OnuId": o.ID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800872 "SerialNumber": o.Sn(),
873 "omciPacket": msg.OmciMsg.Pkt,
874 "msg": msg,
875 "err": sendErr,
876 }).Error("send-TestResult-indication-failed")
877 }
878 }
Girish Gowdraa539f522021-02-15 23:00:45 -0800879 case omci.SynchronizeTimeRequestType:
880 // MDS counter increment is not required for this message type
881 responsePkt, _ = omcilib.CreateSyncTimeResponse(omciPkt, omciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -0800882 case omci.StartSoftwareDownloadRequestType:
883
884 o.ImageSoftwareReceivedSections = 0
885
886 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(omciPkt)
887
888 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(omciPkt, omciMsg); errResp == nil {
889 o.MibDataSync++
890 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
891 onuLogger.WithFields(log.Fields{
892 "OnuId": o.ID,
893 "IntfId": o.PonPortID,
894 "OnuSn": o.Sn(),
895 "Err": err.Error(),
896 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
897 }
898 } else {
899 onuLogger.WithFields(log.Fields{
900 "OmciMsgType": omciMsg.MessageType,
901 "TransCorrId": omciMsg.TransactionID,
902 "Err": err.Error(),
903 "IntfId": o.PonPortID,
904 "SerialNumber": o.Sn(),
905 }).Error("error-while-processing-start-software-download-request")
906 }
907 case omci.DownloadSectionRequestType:
908 if msgObj, err := omcilib.ParseDownloadSectionRequest(omciPkt); err == nil {
909 onuLogger.WithFields(log.Fields{
910 "OmciMsgType": omciMsg.MessageType,
911 "TransCorrId": omciMsg.TransactionID,
912 "EntityInstance": msgObj.EntityInstance,
913 "SectionNumber": msgObj.SectionNumber,
914 "SectionData": msgObj.SectionData,
915 }).Trace("received-download-section-request")
916 o.ImageSoftwareReceivedSections++
917 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
918 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
919 onuLogger.WithFields(log.Fields{
920 "OnuId": o.ID,
921 "IntfId": o.PonPortID,
922 "OnuSn": o.Sn(),
923 "Err": err.Error(),
924 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
925 }
926 }
927 }
928 case omci.DownloadSectionRequestWithResponseType:
929 // NOTE we only need to respond if an ACK is requested
930 responsePkt, err = omcilib.CreateDownloadSectionResponse(omciPkt, omciMsg)
931 if err != nil {
932 onuLogger.WithFields(log.Fields{
933 "OmciMsgType": omciMsg.MessageType,
934 "TransCorrId": omciMsg.TransactionID,
935 "Err": err.Error(),
936 "IntfId": o.PonPortID,
937 "SerialNumber": o.Sn(),
938 }).Error("error-while-processing-create-download-section-response")
939 return
940 }
941 o.ImageSoftwareReceivedSections++
942
943 case omci.EndSoftwareDownloadRequestType:
944
945 // In the startSoftwareDownload we get the image size and the window size.
946 // We calculate how many DownloadSection we should receive and validate
947 // that we got the correct amount when we receive this message
948 success := true
949 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
950 onuLogger.WithFields(log.Fields{
951 "OnuId": o.ID,
952 "IntfId": o.PonPortID,
953 "OnuSn": o.Sn(),
954 "ExpectedSections": o.ImageSoftwareExpectedSections,
955 "ReceivedSections": o.ImageSoftwareReceivedSections,
956 }).Errorf("onu-did-not-receive-all-image-sections")
957 success = false
958 }
959
960 if success {
961 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(omciPkt, omciMsg, me.Success); errResp == nil {
962 o.MibDataSync++
963 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
964 onuLogger.WithFields(log.Fields{
965 "OnuId": o.ID,
966 "IntfId": o.PonPortID,
967 "OnuSn": o.Sn(),
968 "Err": err.Error(),
969 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
970 }
971 } else {
972 onuLogger.WithFields(log.Fields{
973 "OmciMsgType": omciMsg.MessageType,
974 "TransCorrId": omciMsg.TransactionID,
975 "Err": err.Error(),
976 "IntfId": o.PonPortID,
977 "SerialNumber": o.Sn(),
978 }).Error("error-while-processing-end-software-download-request")
979 }
980 } else {
981 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(omciPkt, omciMsg, me.ProcessingError); errResp == nil {
982 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
983 onuLogger.WithFields(log.Fields{
984 "OnuId": o.ID,
985 "IntfId": o.PonPortID,
986 "OnuSn": o.Sn(),
987 "Err": err.Error(),
988 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
989 }
990 }
991 }
992
993 case omci.ActivateSoftwareRequestType:
994 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(omciPkt, omciMsg); errResp == nil {
995 o.MibDataSync++
996 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
997 onuLogger.WithFields(log.Fields{
998 "OnuId": o.ID,
999 "IntfId": o.PonPortID,
1000 "OnuSn": o.Sn(),
1001 "Err": err.Error(),
1002 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1003 }
1004 if msgObj, err := omcilib.ParseActivateSoftwareRequest(omciPkt); err == nil {
1005 o.ActiveImageEntityId = msgObj.EntityInstance
1006 } else {
1007 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1008 }
1009 onuLogger.WithFields(log.Fields{
1010 "OnuId": o.ID,
1011 "IntfId": o.PonPortID,
1012 "OnuSn": o.Sn(),
1013 "ActiveImageEntityId": o.ActiveImageEntityId,
1014 "CommittedImageEntityId": o.CommittedImageEntityId,
1015 }).Info("onu-software-image-activated")
1016
1017 // powercycle the ONU
1018 // we run this in a separate goroutine so that
1019 // the ActivateSoftwareResponse is sent to VOLTHA
1020 // NOTE do we need to wait before rebooting?
1021 go func() {
1022 if err := o.Reboot(10 * time.Second); err != nil {
1023 log.WithFields(log.Fields{
1024 "IntfId": o.PonPortID,
1025 "OnuId": o.ID,
1026 "SerialNumber": o.Sn(),
1027 "err": err,
1028 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1029 }
1030 }()
1031 }
1032 case omci.CommitSoftwareRequestType:
1033 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(omciPkt, omciMsg); errResp == nil {
1034 o.MibDataSync++
1035 if msgObj, err := omcilib.ParseCommitSoftwareRequest(omciPkt); err == nil {
1036 // TODO validate that the image to commit is:
1037 // - active
1038 // - not already committed
1039 o.CommittedImageEntityId = msgObj.EntityInstance
1040 } else {
1041 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1042 }
1043 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1044 onuLogger.WithFields(log.Fields{
1045 "OnuId": o.ID,
1046 "IntfId": o.PonPortID,
1047 "OnuSn": o.Sn(),
1048 "Err": err.Error(),
1049 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1050 }
1051 onuLogger.WithFields(log.Fields{
1052 "OnuId": o.ID,
1053 "IntfId": o.PonPortID,
1054 "OnuSn": o.Sn(),
1055 "ActiveImageEntityId": o.ActiveImageEntityId,
1056 "CommittedImageEntityId": o.CommittedImageEntityId,
1057 }).Info("onu-software-image-committed")
1058 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001059 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001060 onuLogger.WithFields(log.Fields{
1061 "omciBytes": hex.EncodeToString(omciPkt.Data()),
1062 "omciPkt": omciPkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001063 "omciMsgType": omciMsg.MessageType,
1064 "transCorrId": omciMsg.TransactionID,
1065 "IntfId": o.PonPortID,
1066 "SerialNumber": o.Sn(),
1067 }).Warnf("OMCI-message-not-supported")
1068 }
1069
1070 if responsePkt != nil {
1071 if err := o.sendOmciIndication(responsePkt, omciMsg.TransactionID, stream); err != nil {
1072 onuLogger.WithFields(log.Fields{
1073 "IntfId": o.PonPortID,
1074 "SerialNumber": o.Sn(),
1075 "omciPacket": responsePkt,
1076 "omciMsgType": omciMsg.MessageType,
1077 "transCorrId": omciMsg.TransactionID,
1078 }).Errorf("failed-to-send-omci-message: %v", err)
1079 }
1080 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001081
Pragya Arya324337e2020-02-20 14:35:08 +05301082 o.publishOmciEvent(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -08001083}
Pragya Arya324337e2020-02-20 14:35:08 +05301084
Matteo Scandolof9d43412021-01-12 11:11:34 -08001085// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1086func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1087 indication := &openolt.Indication_OmciInd{
1088 OmciInd: &openolt.OmciIndication{
1089 IntfId: o.PonPortID,
1090 OnuId: o.ID,
1091 Pkt: responsePkt,
1092 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001093 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001094 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1095 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001096 }
1097 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001098 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001099 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001100 "omciPacket": indication.OmciInd.Pkt,
1101 "transCorrId": txId,
1102 }).Trace("omci-message-sent")
1103 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001104}
1105
Matteo Scandolo27428702019-10-11 16:21:16 -07001106func (o *Onu) storePortNumber(portNo uint32) {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001107 // NOTE this needed only as long as we don't support multiple UNIs
Matteo Scandolo27428702019-10-11 16:21:16 -07001108 // we need to add support for multiple UNIs
1109 // the action plan is:
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001110 // - refactor the omcisim-sim library to use https://github.com/cboling/omci instead of canned messages
Matteo Scandolo27428702019-10-11 16:21:16 -07001111 // - change the library so that it reports a single UNI and remove this workaroung
1112 // - add support for multiple UNIs in BBSim
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001113 if o.PortNo == 0 || portNo < o.PortNo {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001114 onuLogger.WithFields(log.Fields{
1115 "IntfId": o.PonPortID,
1116 "OnuId": o.ID,
1117 "SerialNumber": o.Sn(),
1118 "OnuPortNo": o.PortNo,
1119 "FlowPortNo": portNo,
1120 }).Debug("Storing ONU portNo")
Matteo Scandolo27428702019-10-11 16:21:16 -07001121 o.PortNo = portNo
1122 }
1123}
1124
William Kurkian0418bc82019-11-06 12:16:24 -05001125func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001126 onuLogger.WithFields(log.Fields{
1127 "IntfId": o.PonPortID,
1128 "OnuId": id,
1129 "SerialNumber": o.Sn(),
1130 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001131 o.ID = id
1132}
1133
Matteo Scandolof9d43412021-01-12 11:11:34 -08001134func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001135 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001136 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001137 "Cookie": msg.Flow.Cookie,
1138 "DstPort": msg.Flow.Classifier.DstPort,
1139 "FlowId": msg.Flow.FlowId,
1140 "FlowType": msg.Flow.FlowType,
1141 "GemportId": msg.Flow.GemportId,
1142 "InnerVlan": msg.Flow.Classifier.IVid,
1143 "IntfId": msg.Flow.AccessIntfId,
1144 "IpProto": msg.Flow.Classifier.IpProto,
1145 "OnuId": msg.Flow.OnuId,
1146 "OnuSn": o.Sn(),
1147 "OuterVlan": msg.Flow.Classifier.OVid,
1148 "PortNo": msg.Flow.PortNo,
1149 "SrcPort": msg.Flow.Classifier.SrcPort,
1150 "UniID": msg.Flow.UniId,
1151 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1152 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1153 "ClassifierIVid": msg.Flow.Classifier.IVid,
1154 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001155 "ReplicateFlow": msg.Flow.ReplicateFlow,
1156 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001157 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001158
Matteo Scandolo813402b2019-10-23 19:24:52 -07001159 if msg.Flow.UniId != 0 {
1160 // as of now BBSim only support a single UNI, so ignore everything that is not targeted to it
1161 onuLogger.WithFields(log.Fields{
1162 "IntfId": o.PonPortID,
1163 "OnuId": o.ID,
1164 "SerialNumber": o.Sn(),
1165 }).Debug("Ignoring flow as it's not for the first UNI")
1166 return
1167 }
1168
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001169 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001170
1171 var gemPortId uint32
1172 if msg.Flow.ReplicateFlow {
1173 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1174 // first available gemport (we only need to send one packet)
1175 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1176 gemPortId = msg.Flow.PbitToGemport[0]
1177 } else {
1178 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1179 gemPortId = uint32(msg.Flow.GemportId)
1180 }
1181 o.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001182
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001183 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo27428702019-10-11 16:21:16 -07001184 // NOTE storing the PortNO, it's needed when sending PacketIndications
Matteo Scandolo813402b2019-10-23 19:24:52 -07001185 o.storePortNumber(uint32(msg.Flow.PortNo))
Matteo Scandolo4a036262020-08-17 15:56:13 -07001186
1187 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001188 s.HandleAuth()
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001189 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001190 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1191 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001192 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo99f18462019-10-28 14:14:28 -07001193
Matteo Scandolo4a036262020-08-17 15:56:13 -07001194 for _, s := range o.Services {
Matteo Scandolobd875b32020-09-18 17:46:31 -07001195 s.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001196 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001197 }
1198}
1199
Matteo Scandolof9d43412021-01-12 11:11:34 -08001200func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001201 onuLogger.WithFields(log.Fields{
1202 "IntfId": o.PonPortID,
1203 "OnuId": o.ID,
1204 "SerialNumber": o.Sn(),
1205 "FlowId": msg.Flow.FlowId,
1206 "FlowType": msg.Flow.FlowType,
1207 }).Debug("ONU receives FlowRemove")
1208
1209 for idx, flow := range o.FlowIds {
1210 // If the gemport is found, delete it from local cache.
1211 if flow == msg.Flow.FlowId {
1212 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1213 break
1214 }
1215 }
1216
1217 if len(o.FlowIds) == 0 {
1218 onuLogger.WithFields(log.Fields{
1219 "IntfId": o.PonPortID,
1220 "OnuId": o.ID,
1221 "SerialNumber": o.Sn(),
1222 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001223
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301224 // check if ONU delete is performed and
1225 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001226 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301227 close(o.Channel)
1228 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001229 }
1230}
1231
Matteo Scandolocedde462021-03-09 17:37:16 -08001232func (o *Onu) Reboot(timeout time.Duration) error {
1233 onuLogger.WithFields(log.Fields{
1234 "IntfId": o.PonPortID,
1235 "OnuId": o.ID,
1236 "SerialNumber": o.Sn(),
1237 }).Debug("shutting-down-onu")
1238 if err := o.HandleShutdownONU(); err != nil {
1239 return err
1240 }
1241 time.Sleep(timeout)
1242 onuLogger.WithFields(log.Fields{
1243 "IntfId": o.PonPortID,
1244 "OnuId": o.ID,
1245 "SerialNumber": o.Sn(),
1246 }).Debug("power-on-onu")
1247 if err := o.HandlePowerOnONU(); err != nil {
1248 return err
1249 }
1250 return nil
1251}
1252
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001253// BBR methods
1254
1255func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1256 omciMsg := openolt.OmciMsg{
1257 IntfId: intfId,
1258 OnuId: onuId,
1259 Pkt: pktBytes,
1260 }
1261
1262 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1263 log.WithFields(log.Fields{
1264 "IntfId": intfId,
1265 "OnuId": onuId,
1266 "SerialNumber": common.OnuSnToString(sn),
1267 "Pkt": omciMsg.Pkt,
1268 }).Fatalf("Failed to send MIB Reset")
1269 }
1270 log.WithFields(log.Fields{
1271 "IntfId": intfId,
1272 "OnuId": onuId,
1273 "SerialNumber": common.OnuSnToString(sn),
1274 "Pkt": omciMsg.Pkt,
1275 }).Tracef("Sent OMCI message %s", msgType)
1276}
1277
1278func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1279 var next uint16
1280 if len(highPriority) > 0 && highPriority[0] {
1281 next = onu.hpTid
1282 onu.hpTid += 1
1283 if onu.hpTid < 0x8000 {
1284 onu.hpTid = 0x8000
1285 }
1286 } else {
1287 next = onu.tid
1288 onu.tid += 1
1289 if onu.tid >= 0x8000 {
1290 onu.tid = 1
1291 }
1292 }
1293 return next
1294}
1295
1296// TODO move this method in responders/omcisim
1297func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1298 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1299 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1300}
1301
Matteo Scandolof9d43412021-01-12 11:11:34 -08001302// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1303func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1304
1305 // we need to encode the packet in HEX
1306 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1307 hex.Encode(pkt, msg.OmciInd.Pkt)
1308 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1309 if err != nil {
1310 log.WithFields(log.Fields{
1311 "IntfId": o.PonPortID,
1312 "SerialNumber": o.Sn(),
1313 "omciPacket": msg.OmciInd.Pkt,
1314 }).Error("BBR Cannot parse OMCI packet")
1315 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001316
1317 log.WithFields(log.Fields{
1318 "IntfId": msg.OmciInd.IntfId,
1319 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001320 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001321 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001322 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301323 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001324 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001325 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001326 log.WithFields(log.Fields{
1327 "IntfId": msg.OmciInd.IntfId,
1328 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001329 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001330 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001331 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001332 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001333 case omci.MibResetResponseType:
1334 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1335 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1336 case omci.MibUploadResponseType:
1337 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1338 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1339 case omci.MibUploadNextResponseType:
1340 o.seqNumber++
1341
1342 if o.seqNumber > 290 {
1343 // NOTE we are done with the MIB Upload (290 is the number of messages the omci-sim library will respond to)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001344 // start sending the flows, we don't care about the OMCI setup in BBR, just that a lot of messages can go through
Matteo Scandolocedde462021-03-09 17:37:16 -08001345 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001346 onuLogger.WithFields(log.Fields{
1347 "OnuId": o.ID,
1348 "IntfId": o.PonPortID,
1349 "OnuSn": o.Sn(),
1350 }).Errorf("Error while transitioning ONU State %v", err)
1351 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001352 } else {
1353 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1354 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001355 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001356 }
1357}
1358
1359func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1360
1361 classifierProto := openolt.Classifier{
1362 EthType: uint32(layers.EthernetTypeEAPOL),
1363 OVid: 4091,
1364 }
1365
1366 actionProto := openolt.Action{}
1367
1368 downstreamFlow := openolt.Flow{
1369 AccessIntfId: int32(o.PonPortID),
1370 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001371 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001372 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001373 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001374 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001375 Classifier: &classifierProto,
1376 Action: &actionProto,
1377 Priority: int32(100),
1378 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001379 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1380 // AllocId and GemPorts need to be unique per PON
1381 // for now use the ONU-ID, will need to change once we support multiple UNIs
1382 AllocId: int32(o.ID),
1383 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001384 }
1385
1386 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1387 log.WithFields(log.Fields{
1388 "IntfId": o.PonPortID,
1389 "OnuId": o.ID,
1390 "FlowId": downstreamFlow.FlowId,
1391 "PortNo": downstreamFlow.PortNo,
1392 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001393 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001394 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001395 }
1396 log.WithFields(log.Fields{
1397 "IntfId": o.PonPortID,
1398 "OnuId": o.ID,
1399 "FlowId": downstreamFlow.FlowId,
1400 "PortNo": downstreamFlow.PortNo,
1401 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1402 }).Info("Sent EAPOL Flow")
1403}
1404
1405func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001406
1407 // BBR only works with a single service (ATT HSIA)
1408 hsia := o.Services[0].(*Service)
1409
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001410 classifierProto := openolt.Classifier{
1411 EthType: uint32(layers.EthernetTypeIPv4),
1412 SrcPort: uint32(68),
1413 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001414 OVid: uint32(hsia.CTag),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001415 }
1416
1417 actionProto := openolt.Action{}
1418
1419 downstreamFlow := openolt.Flow{
1420 AccessIntfId: int32(o.PonPortID),
1421 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001422 UniId: int32(0), // FIXME do not hardcode this
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001423 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001424 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001425 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001426 Classifier: &classifierProto,
1427 Action: &actionProto,
1428 Priority: int32(100),
1429 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001430 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1431 // AllocId and GemPorts need to be unique per PON
1432 // for now use the ONU-ID, will need to change once we support multiple UNIs
1433 AllocId: int32(o.ID),
1434 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001435 }
1436
1437 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1438 log.WithFields(log.Fields{
1439 "IntfId": o.PonPortID,
1440 "OnuId": o.ID,
1441 "FlowId": downstreamFlow.FlowId,
1442 "PortNo": downstreamFlow.PortNo,
1443 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001444 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001445 }).Fatalf("Failed to send DHCP Flow")
1446 }
1447 log.WithFields(log.Fields{
1448 "IntfId": o.PonPortID,
1449 "OnuId": o.ID,
1450 "FlowId": downstreamFlow.FlowId,
1451 "PortNo": downstreamFlow.PortNo,
1452 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1453 }).Info("Sent DHCP Flow")
1454}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301455
1456// DeleteFlow method search and delete flowKey from the onu flows slice
1457func (onu *Onu) DeleteFlow(key FlowKey) {
1458 for pos, flowKey := range onu.Flows {
1459 if flowKey == key {
1460 // delete the flowKey by shifting all flowKeys by one
1461 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1462 t := make([]FlowKey, len(onu.Flows))
1463 copy(t, onu.Flows)
1464 onu.Flows = t
1465 break
1466 }
1467 }
1468}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301469
1470func (onu *Onu) ReDiscoverOnu() {
1471 // Wait for few seconds to be sure of the cleanup
1472 time.Sleep(5 * time.Second)
1473
1474 onuLogger.WithFields(log.Fields{
1475 "IntfId": onu.PonPortID,
1476 "OnuId": onu.ID,
1477 "OnuSn": onu.Sn(),
1478 }).Debug("Send ONU Re-Discovery")
1479
1480 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001481 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301482 log.WithFields(log.Fields{
1483 "IntfId": onu.PonPortID,
1484 "OnuSn": onu.Sn(),
1485 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001486 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301487 }
1488
Matteo Scandolocedde462021-03-09 17:37:16 -08001489 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301490 log.WithFields(log.Fields{
1491 "IntfId": onu.PonPortID,
1492 "OnuSn": onu.Sn(),
1493 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001494 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301495 }
1496}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001497
1498func (onu *Onu) addGemPortToService(gemport uint32, ethType uint32, oVlan uint32, iVlan uint32) {
1499 for _, s := range onu.Services {
1500 if service, ok := s.(*Service); ok {
1501 // EAPOL is a strange case, as packets are untagged
1502 // but we assume we will have a single service requiring EAPOL
1503 if ethType == uint32(layers.EthernetTypeEAPOL) && service.NeedsEapol {
1504 service.GemPort = gemport
1505 }
1506
1507 // For DHCP services we single tag the outgoing packets,
1508 // thus the flow only contains the CTag and we can use that to match the service
1509 if ethType == uint32(layers.EthernetTypeIPv4) && service.NeedsDhcp && service.CTag == int(oVlan) {
1510 service.GemPort = gemport
1511 }
1512
1513 // for dataplane services match both C and S tags
1514 if service.CTag == int(iVlan) && service.STag == int(oVlan) {
1515 service.GemPort = gemport
1516 }
1517 }
1518 }
1519}
1520
1521func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
1522 for _, s := range onu.Services {
1523 service := s.(*Service)
1524 if service.HwAddress.String() == macAddress.String() {
1525 return service, nil
1526 }
1527 }
1528 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1529}