blob: fd7eca047ead9f90f781a0fac32b8e866cf20862 [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"
25 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
26 me "github.com/opencord/omci-lib-go/generated"
27 "strconv"
28
Matteo Scandolo4a036262020-08-17 15:56:13 -070029 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
30 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
31 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010032 "net"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010033 "time"
34
Matteo Scandolo3bc73742019-08-20 14:04:04 -070035 "github.com/google/gopacket/layers"
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070036 "github.com/jpillora/backoff"
Matteo Scandolo4747d292019-08-05 11:50:18 -070037 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070038 "github.com/opencord/bbsim/internal/common"
39 omcilib "github.com/opencord/bbsim/internal/common/omci"
Matteo Scandolof9d43412021-01-12 11:11:34 -080040 "github.com/opencord/omci-lib-go"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070041 "github.com/opencord/voltha-protos/v4/go/openolt"
42 "github.com/opencord/voltha-protos/v4/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070043 log "github.com/sirupsen/logrus"
44)
45
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070046var onuLogger = log.WithFields(log.Fields{
47 "module": "ONU",
48})
49
Matteo Scandolocedde462021-03-09 17:37:16 -080050const (
51 // ONU transitions
52 OnuTxInitialize = "initialize"
53 OnuTxDiscover = "discover"
54 OnuTxEnable = "enable"
55 OnuTxDisable = "disable"
56 OnuTxPonDisable = "pon_disable"
57 OnuTxStartImageDownload = "start_image_download"
58 OnuTxProgressImageDownload = "progress_image_download"
59 OnuTxCompleteImageDownload = "complete_image_download"
60 OnuTxFailImageDownload = "fail_image_download"
61 OnuTxActivateImage = "activate_image"
62 OnuTxCommitImage = "commit_image"
63
64 // ONU States
65 OnuStateCreated = "created"
66 OnuStateInitialized = "initialized"
67 OnuStateDiscovered = "discovered"
68 OnuStateEnabled = "enabled"
69 OnuStateDisabled = "disabled"
70 OnuStatePonDisabled = "pon_disabled"
71 OnuStateImageDownloadStarted = "image_download_started"
72 OnuStateImageDownloadInProgress = "image_download_in_progress"
73 OnuStateImageDownloadComplete = "image_download_completed"
74 OnuStateImageDownloadError = "image_download_error"
75 OnuStateImageActivated = "software_image_activated"
76 OnuStateImageCommitted = "software_image_committed"
77
78 // BBR ONU States and Transitions
79 BbrOnuTxSendEapolFlow = "send_eapol_flow"
80 BbrOnuStateEapolFlowSent = "eapol_flow_sent"
81 BbrOnuTxSendDhcpFlow = "send_dhcp_flow"
82 BbrOnuStateDhcpFlowSent = "dhcp_flow_sent"
83)
84
Pragya Arya8bdb4532020-03-02 17:08:09 +053085type FlowKey struct {
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070086 ID uint64
Pragya Arya8bdb4532020-03-02 17:08:09 +053087 Direction string
88}
89
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070090type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -080091 ID uint32
92 PonPortID uint32
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070093 PonPort *PonPort
Matteo Scandoloe811ae92019-12-10 17:50:14 -080094 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +053095 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
96 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandolo4a036262020-08-17 15:56:13 -070097
98 Services []ServiceIf
99
100 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800101 // ONU State
Matteo Scandolo27428702019-10-11 16:21:16 -0700102 // PortNo comes with flows and it's used when sending packetIndications,
103 // There is one PortNo per UNI Port, for now we're only storing the first one
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700104 // FIXME add support for multiple UNIs (each UNI has a different PortNo)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700105 PortNo uint32
106 // deprecated (gemPort is on a Service basis)
Matteo Scandolo4a036262020-08-17 15:56:13 -0700107 GemPortAdded bool
108 Flows []FlowKey
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700109 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700110
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700111 OperState *fsm.FSM
112 SerialNumber *openolt.SerialNumber
113
Matteo Scandolof9d43412021-01-12 11:11:34 -0800114 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700115
116 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800117 MibDataSync uint8
118 ImageSoftwareExpectedSections int
119 ImageSoftwareReceivedSections int
120 ActiveImageEntityId uint16
121 CommittedImageEntityId uint16
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800122
123 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700124 tid uint16
125 hpTid uint16
126 seqNumber uint16
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700127
Anand S Katti09541352020-01-29 15:54:01 +0530128 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
129 TrafficSchedulers *tech_profile.TrafficSchedulers
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700130}
131
Matteo Scandolo99f18462019-10-28 14:14:28 -0700132func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700133 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700134}
135
Matteo Scandolo4a036262020-08-17 15:56:13 -0700136func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, isMock bool) *Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700137
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700138 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800139 ID: id,
140 PonPortID: pon.ID,
141 PonPort: pon,
142 PortNo: 0,
143 tid: 0x1,
144 hpTid: 0x8000,
145 seqNumber: 0,
146 DoneChannel: make(chan bool, 1),
147 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
148 Flows: []FlowKey{},
149 DiscoveryDelay: delay,
150 MibDataSync: 0,
151 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
152 ImageSoftwareReceivedSections: 0,
153 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
154 CommittedImageEntityId: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700155 }
Pragya Arya2225f202020-01-29 18:05:01 +0530156 o.SerialNumber = o.NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700157 // NOTE this state machine is used to track the operational
158 // state as requested by VOLTHA
159 o.OperState = getOperStateFSM(func(e *fsm.Event) {
160 onuLogger.WithFields(log.Fields{
161 "ID": o.ID,
162 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
163 })
164
165 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
166 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800167 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700168 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700169 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800170 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
171 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
172 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100173 // 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 -0800174 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530175 // 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 -0800176 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStatePonDisabled},
177 // Software Image Download related states
178 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError}, Dst: OnuStateImageDownloadStarted},
179 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
180 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
181 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
182 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
183 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700184 // BBR States
185 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800186 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
187 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700188 },
189 fsm.Callbacks{
190 "enter_state": func(e *fsm.Event) {
191 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700192 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100193 "enter_initialized": func(e *fsm.Event) {
194 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800195 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800196
Matteo Scandolocedde462021-03-09 17:37:16 -0800197 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800198 onuLogger.WithFields(log.Fields{
199 "OnuId": o.ID,
200 "IntfId": o.PonPortID,
201 "OnuSn": o.Sn(),
202 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
203 }
204
Pragya Arya1cbefa42020-01-13 12:15:29 +0530205 if !isMock {
206 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700207 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530208 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100209 },
210 "enter_discovered": func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800211 msg := bbsim.Message{
212 Type: bbsim.OnuDiscIndication,
213 Data: bbsim.OnuDiscIndicationMessage{
214 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100215 },
216 }
217 o.Channel <- msg
218 },
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700219 "enter_enabled": func(event *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800220 msg := bbsim.Message{
221 Type: bbsim.OnuIndication,
222 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700223 OnuSN: o.SerialNumber,
224 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800225 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700226 },
227 }
228 o.Channel <- msg
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700229
230 // Once the ONU is enabled start listening for packets
231 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700232 s.Initialize(o.PonPort.Olt.OpenoltStream)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700233 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700234 },
235 "enter_disabled": func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700236
237 // clean the ONU state
Matteo Scandolo328c5f02020-06-26 14:16:39 -0700238 o.GemPortAdded = false
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700239 o.PortNo = 0
240 o.Flows = []FlowKey{}
241
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700242 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800243 if err := o.OperState.Event("disable"); err != nil {
244 onuLogger.WithFields(log.Fields{
245 "OnuId": o.ID,
246 "IntfId": o.PonPortID,
247 "OnuSn": o.Sn(),
248 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
249 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700250
251 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800252 msg := bbsim.Message{
253 Type: bbsim.OnuIndication,
254 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700255 OnuSN: o.SerialNumber,
256 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800257 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700258 },
259 }
260 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530261
262 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100263 // terminate the ONU's ProcessOnuMessages Go routine
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530264 if len(o.FlowIds) == 0 {
265 close(o.Channel)
266 }
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700267
268 for _, s := range o.Services {
269 s.Disable()
270 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700271 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700272 // BBR states
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700273 "enter_eapol_flow_sent": func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800274 msg := bbsim.Message{
275 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700276 }
277 o.Channel <- msg
278 },
279 "enter_dhcp_flow_sent": func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800280 msg := bbsim.Message{
281 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700282 }
283 o.Channel <- msg
284 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700285 },
286 )
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100287
Matteo Scandolo27428702019-10-11 16:21:16 -0700288 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700289}
290
William Kurkian0418bc82019-11-06 12:16:24 -0500291func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700292 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700293 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700294 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700295 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700296 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
297}
298
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100299// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000300func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700301 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100302 "onuID": o.ID,
303 "onuSN": o.Sn(),
304 "ponPort": o.PonPortID,
305 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700306
David Bainbridge103cf022019-12-16 20:11:35 +0000307loop:
308 for {
309 select {
310 case <-ctx.Done():
311 onuLogger.WithFields(log.Fields{
312 "onuID": o.ID,
313 "onuSN": o.Sn(),
314 }).Tracef("ONU message handling canceled via context")
315 break loop
316 case message, ok := <-o.Channel:
317 if !ok || ctx.Err() != nil {
318 onuLogger.WithFields(log.Fields{
319 "onuID": o.ID,
320 "onuSN": o.Sn(),
321 }).Tracef("ONU message handling canceled via channel close")
322 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700323 }
David Bainbridge103cf022019-12-16 20:11:35 +0000324 onuLogger.WithFields(log.Fields{
325 "onuID": o.ID,
326 "onuSN": o.Sn(),
327 "messageType": message.Type,
328 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700329
David Bainbridge103cf022019-12-16 20:11:35 +0000330 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800331 case bbsim.OnuDiscIndication:
332 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000333 // 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 +0530334 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000335 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800336 case bbsim.OnuIndication:
337 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000338 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800339 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800340 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800341 msg, _ := message.Data.(bbsim.OmciMessage)
342 o.handleOmciRequest(msg, stream)
343 case bbsim.UniStatusAlarm:
344 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
345 pkt := omcilib.CreateUniStatusAlarm(msg.AdminState, msg.EntityID)
346 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
347 onuLogger.WithFields(log.Fields{
348 "IntfId": o.PonPortID,
349 "SerialNumber": o.Sn(),
350 "omciPacket": pkt,
351 "adminState": msg.AdminState,
352 "entityID": msg.EntityID,
353 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
354 }
355 onuLogger.WithFields(log.Fields{
356 "IntfId": o.PonPortID,
357 "SerialNumber": o.Sn(),
358 "omciPacket": pkt,
359 "adminState": msg.AdminState,
360 "entityID": msg.EntityID,
361 }).Trace("UNI-Link-alarm-sent")
362 case bbsim.FlowAdd:
363 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700364 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800365 case bbsim.FlowRemoved:
366 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700367 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800368 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700369
Matteo Scandolof9d43412021-01-12 11:11:34 -0800370 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000371
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700372 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000373 "IntfId": msg.IntfId,
374 "OnuId": msg.OnuId,
375 "pktType": msg.Type,
376 }).Trace("Received OnuPacketOut Message")
377
Matteo Scandolo618a6582020-09-09 12:21:29 -0700378 if msg.Type == packetHandlers.EAPOL || msg.Type == packetHandlers.DHCP {
379
380 service, err := o.findServiceByMacAddress(msg.MacAddress)
381 if err != nil {
382 onuLogger.WithFields(log.Fields{
383 "IntfId": msg.IntfId,
384 "OnuId": msg.OnuId,
385 "pktType": msg.Type,
386 "MacAddress": msg.MacAddress,
387 "Pkt": hex.EncodeToString(msg.Packet.Data()),
388 "OnuSn": o.Sn(),
389 }).Error("Cannot find Service associated with packet")
390 return
391 }
392 service.PacketCh <- msg
393 } else if msg.Type == packetHandlers.IGMP {
394 // if it's an IGMP packet we assume we have a single IGMP service
395 for _, s := range o.Services {
396 service := s.(*Service)
397
398 if service.NeedsIgmp {
399 service.PacketCh <- msg
400 }
401 }
David Bainbridge103cf022019-12-16 20:11:35 +0000402 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700403
Matteo Scandolof9d43412021-01-12 11:11:34 -0800404 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000405 // NOTE we only receive BBR packets here.
406 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
407 // 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 -0800408 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000409
410 log.WithFields(log.Fields{
411 "IntfId": msg.IntfId,
412 "OnuId": msg.OnuId,
413 "pktType": msg.Type,
414 }).Trace("Received OnuPacketIn Message")
415
416 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700417 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 +0000418 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700419 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000420 }
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700421 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800422 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800423 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800424 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
425 o.handleOmciResponse(msg, client)
426 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000427 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800428 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000429 o.sendDhcpFlow(client)
430 default:
431 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700432 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700433 }
434 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100435 onuLogger.WithFields(log.Fields{
436 "onuID": o.ID,
437 "onuSN": o.Sn(),
438 }).Debug("Stopped handling ONU Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700439}
440
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100441func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700442
443 sn := new(openolt.SerialNumber)
444
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700445 //sn = new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700446 sn.VendorId = []byte("BBSM")
447 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
448
449 return sn
450}
451
Matteo Scandolof9d43412021-01-12 11:11:34 -0800452func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700453 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800454 IntfId: o.PonPortID,
455 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700456 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700457
Matteo Scandolo4747d292019-08-05 11:50:18 -0700458 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700459 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700460 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700461 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700462
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700463 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800464 "IntfId": o.PonPortID,
465 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700466 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700467 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800468 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800469
470 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
471 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800472 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800473 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800474 o.sendOnuDiscIndication(msg, stream)
475 }
476 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700477}
478
Matteo Scandolof9d43412021-01-12 11:11:34 -0800479func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700480 // NOTE voltha returns an ID, but if we use that ID then it complains:
481 // expected_onu_id: 1, received_onu_id: 1024, event: ONU-id-mismatch, can happen if both voltha and the olt rebooted
482 // so we're using the internal ID that is 1
483 // o.ID = msg.OnuID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700484
485 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700486 IntfId: o.PonPortID,
487 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700488 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700489 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700490 SerialNumber: o.SerialNumber,
491 }}
492 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800493 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700494 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700495 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700496 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700497 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700498 "IntfId": o.PonPortID,
499 "OnuId": o.ID,
500 "OperState": msg.OperState.String(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700501 "AdminState": msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700502 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700503 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700504
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700505}
506
Matteo Scandolof9d43412021-01-12 11:11:34 -0800507func (o *Onu) HandleShutdownONU() error {
508
509 dyingGasp := pb.ONUAlarmRequest{
510 AlarmType: "DYING_GASP",
511 SerialNumber: o.Sn(),
512 Status: "on",
513 }
514
515 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
516 onuLogger.WithFields(log.Fields{
517 "OnuId": o.ID,
518 "IntfId": o.PonPortID,
519 "OnuSn": o.Sn(),
520 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
521 return err
522 }
523
524 losReq := pb.ONUAlarmRequest{
525 AlarmType: "ONU_ALARM_LOS",
526 SerialNumber: o.Sn(),
527 Status: "on",
528 }
529
530 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
531 onuLogger.WithFields(log.Fields{
532 "OnuId": o.ID,
533 "IntfId": o.PonPortID,
534 "OnuSn": o.Sn(),
535 }).Errorf("Cannot send LOS: %s", err.Error())
536
537 return err
538 }
539
540 // TODO if it's the last ONU on the PON, then send a PON LOS
541
Matteo Scandolocedde462021-03-09 17:37:16 -0800542 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800543 onuLogger.WithFields(log.Fields{
544 "OnuId": o.ID,
545 "IntfId": o.PonPortID,
546 "OnuSn": o.Sn(),
547 }).Errorf("Cannot shutdown ONU: %s", err.Error())
548 return err
549 }
550
551 return nil
552}
553
554func (o *Onu) HandlePowerOnONU() error {
555 intitalState := o.InternalState.Current()
556
557 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800558 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
559 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800560 onuLogger.WithFields(log.Fields{
561 "OnuId": o.ID,
562 "IntfId": o.PonPortID,
563 "OnuSn": o.Sn(),
564 }).Errorf("Cannot poweron ONU: %s", err.Error())
565 return err
566 }
567 }
568
569 // turn off the LOS Alarm
570 losReq := pb.ONUAlarmRequest{
571 AlarmType: "ONU_ALARM_LOS",
572 SerialNumber: o.Sn(),
573 Status: "off",
574 }
575
576 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
577 onuLogger.WithFields(log.Fields{
578 "OnuId": o.ID,
579 "IntfId": o.PonPortID,
580 "OnuSn": o.Sn(),
581 }).Errorf("Cannot send LOS: %s", err.Error())
582 return err
583 }
584
585 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800586 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800587 onuLogger.WithFields(log.Fields{
588 "OnuId": o.ID,
589 "IntfId": o.PonPortID,
590 "OnuSn": o.Sn(),
591 }).Errorf("Cannot poweron ONU: %s", err.Error())
592 return err
593 }
594
595 // move o directly to enable state only when its a powercycle case
596 // in case of first time o poweron o will be moved to enable on
597 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800598 if intitalState == OnuStateDisabled {
599 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800600 onuLogger.WithFields(log.Fields{
601 "OnuId": o.ID,
602 "IntfId": o.PonPortID,
603 "OnuSn": o.Sn(),
604 }).Errorf("Cannot enable ONU: %s", err.Error())
605 return err
606 }
607 }
608
609 return nil
610}
611
612func (o *Onu) SetAlarm(alarmType string, status string) error {
613 alarmReq := pb.ONUAlarmRequest{
614 AlarmType: alarmType,
615 SerialNumber: o.Sn(),
616 Status: status,
617 }
618
619 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
620 if err != nil {
621 return err
622 }
623 return nil
624}
625
626func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530627 if olt.PublishEvents {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800628 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
Pragya Arya324337e2020-02-20 14:35:08 +0530629 if err != nil {
630 log.Errorf("error in getting msgType %v", err)
631 return
632 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800633 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530634 o.seqNumber = 0
635 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800636 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530637 o.seqNumber++
638 if o.seqNumber > 290 {
639 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
640 }
641 }
642 }
643}
644
Scott Bakerb90c4312020-03-12 21:33:25 -0700645// Create a TestResponse packet and send it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800646func (o *Onu) sendTestResult(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
647 resp, err := omcilib.BuildTestResult(msg.OmciMsg.Pkt)
Scott Bakerb90c4312020-03-12 21:33:25 -0700648 if err != nil {
649 return err
650 }
651
652 var omciInd openolt.OmciIndication
653 omciInd.IntfId = o.PonPortID
654 omciInd.OnuId = o.ID
655 omciInd.Pkt = resp
656
657 omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
658 if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
Scott Bakerb90c4312020-03-12 21:33:25 -0700659 return err
660 }
661 onuLogger.WithFields(log.Fields{
662 "IntfId": o.PonPortID,
663 "SerialNumber": o.Sn(),
664 "omciPacket": omciInd.Pkt,
665 }).Tracef("Sent TestResult OMCI message")
666
667 return nil
668}
669
Matteo Scandolof9d43412021-01-12 11:11:34 -0800670// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
671// and generate the appropriate response to it
672func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
673
674 omciPkt, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
675 if err != nil {
676 log.WithFields(log.Fields{
677 "IntfId": o.PonPortID,
678 "SerialNumber": o.Sn(),
Matteo Scandolocedde462021-03-09 17:37:16 -0800679 "omciPacket": omcilib.HexDecode(msg.OmciMsg.Pkt),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800680 }).Error("cannot-parse-OMCI-packet")
681 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700682
683 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800684 "omciMsgType": omciMsg.MessageType,
685 "transCorrId": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
686 "DeviceIdent": omciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700687 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700688 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800689 }).Trace("omci-message-decoded")
690
691 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800692 var errResp error
Matteo Scandolof9d43412021-01-12 11:11:34 -0800693 switch omciMsg.MessageType {
694 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800695 onuLogger.WithFields(log.Fields{
696 "IntfId": o.PonPortID,
697 "OnuId": o.ID,
698 "SerialNumber": o.Sn(),
699 }).Debug("received-mib-reset-request-resetting-mds")
Girish Gowdrae2683102021-03-05 08:24:26 -0800700 if responsePkt, errResp = omcilib.CreateMibResetResponse(omciMsg.TransactionID); errResp == nil {
701 o.MibDataSync = 0
702 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800703 case omci.MibUploadRequestType:
704 responsePkt, _ = omcilib.CreateMibUploadResponse(omciMsg.TransactionID)
705 case omci.MibUploadNextRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800706 responsePkt, _ = omcilib.CreateMibUploadNextResponse(omciPkt, omciMsg, o.MibDataSync)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800707 case omci.GetRequestType:
Matteo Scandolocedde462021-03-09 17:37:16 -0800708 responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId, o.CommittedImageEntityId)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800709 case omci.SetRequestType:
Girish Gowdrae2683102021-03-05 08:24:26 -0800710 if responsePkt, errResp = omcilib.CreateSetResponse(omciPkt, omciMsg); errResp == nil {
711 o.MibDataSync++
712 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800713
714 msgObj, _ := omcilib.ParseSetRequest(omciPkt)
715 switch msgObj.EntityClass {
716 case me.PhysicalPathTerminationPointEthernetUniClassID:
717 // if we're Setting a PPTP state
718 // we need to send the appropriate alarm
719
720 if msgObj.EntityInstance == 257 {
721 // for now we're only caring about the first UNI
722 // NOTE that the EntityID for the UNI port is for now hardcoded in
723 // omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
724 // are reported during the MIB Upload sequence
725 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
726 msg := bbsim.Message{
727 Type: bbsim.UniStatusAlarm,
728 Data: bbsim.UniStatusAlarmMessage{
729 OnuSN: o.SerialNumber,
730 OnuID: o.ID,
731 AdminState: adminState,
732 EntityID: msgObj.EntityInstance,
733 },
734 }
735 o.Channel <- msg
736 }
737 }
738 case omci.CreateRequestType:
Girish Gowdrae2683102021-03-05 08:24:26 -0800739 if responsePkt, errResp = omcilib.CreateCreateResponse(omciPkt, omciMsg); errResp == nil {
740 o.MibDataSync++
741 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800742 case omci.DeleteRequestType:
Girish Gowdrae2683102021-03-05 08:24:26 -0800743 if responsePkt, errResp = omcilib.CreateDeleteResponse(omciPkt, omciMsg); errResp == nil {
744 o.MibDataSync++
745 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800746 case omci.RebootRequestType:
747
748 responsePkt, _ = omcilib.CreateRebootResponse(omciPkt, omciMsg)
749
750 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800751 // we run this in a separate goroutine so that
752 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800753 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800754 if err := o.Reboot(10 * time.Second); err != nil {
755 log.WithFields(log.Fields{
756 "IntfId": o.PonPortID,
757 "OnuId": o.ID,
758 "SerialNumber": o.Sn(),
759 "err": err,
760 }).Error("cannot-reboot-onu-after-omci-reboot-request")
761 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800762 }()
763 case omci.TestRequestType:
764
765 // Test message is special, it requires sending two packets:
766 // first packet: TestResponse, says whether test was started successully, handled by omci-sim
767 // second packet, TestResult, reports the result of running the self-test
768 // TestResult can come some time after a TestResponse
769 // TODO: Implement some delay between the TestResponse and the TestResult
770 isTest, err := omcilib.IsTestRequest(msg.OmciMsg.Pkt)
771 if (err == nil) && (isTest) {
772 if sendErr := o.sendTestResult(msg, stream); sendErr != nil {
773 onuLogger.WithFields(log.Fields{
774 "IntfId": o.PonPortID,
Matteo Scandolocedde462021-03-09 17:37:16 -0800775 "OnuId": o.ID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800776 "SerialNumber": o.Sn(),
777 "omciPacket": msg.OmciMsg.Pkt,
778 "msg": msg,
779 "err": sendErr,
780 }).Error("send-TestResult-indication-failed")
781 }
782 }
Girish Gowdraa539f522021-02-15 23:00:45 -0800783 case omci.SynchronizeTimeRequestType:
784 // MDS counter increment is not required for this message type
785 responsePkt, _ = omcilib.CreateSyncTimeResponse(omciPkt, omciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -0800786 case omci.StartSoftwareDownloadRequestType:
787
788 o.ImageSoftwareReceivedSections = 0
789
790 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(omciPkt)
791
792 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(omciPkt, omciMsg); errResp == nil {
793 o.MibDataSync++
794 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
795 onuLogger.WithFields(log.Fields{
796 "OnuId": o.ID,
797 "IntfId": o.PonPortID,
798 "OnuSn": o.Sn(),
799 "Err": err.Error(),
800 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
801 }
802 } else {
803 onuLogger.WithFields(log.Fields{
804 "OmciMsgType": omciMsg.MessageType,
805 "TransCorrId": omciMsg.TransactionID,
806 "Err": err.Error(),
807 "IntfId": o.PonPortID,
808 "SerialNumber": o.Sn(),
809 }).Error("error-while-processing-start-software-download-request")
810 }
811 case omci.DownloadSectionRequestType:
812 if msgObj, err := omcilib.ParseDownloadSectionRequest(omciPkt); err == nil {
813 onuLogger.WithFields(log.Fields{
814 "OmciMsgType": omciMsg.MessageType,
815 "TransCorrId": omciMsg.TransactionID,
816 "EntityInstance": msgObj.EntityInstance,
817 "SectionNumber": msgObj.SectionNumber,
818 "SectionData": msgObj.SectionData,
819 }).Trace("received-download-section-request")
820 o.ImageSoftwareReceivedSections++
821 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
822 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
823 onuLogger.WithFields(log.Fields{
824 "OnuId": o.ID,
825 "IntfId": o.PonPortID,
826 "OnuSn": o.Sn(),
827 "Err": err.Error(),
828 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
829 }
830 }
831 }
832 case omci.DownloadSectionRequestWithResponseType:
833 // NOTE we only need to respond if an ACK is requested
834 responsePkt, err = omcilib.CreateDownloadSectionResponse(omciPkt, omciMsg)
835 if err != nil {
836 onuLogger.WithFields(log.Fields{
837 "OmciMsgType": omciMsg.MessageType,
838 "TransCorrId": omciMsg.TransactionID,
839 "Err": err.Error(),
840 "IntfId": o.PonPortID,
841 "SerialNumber": o.Sn(),
842 }).Error("error-while-processing-create-download-section-response")
843 return
844 }
845 o.ImageSoftwareReceivedSections++
846
847 case omci.EndSoftwareDownloadRequestType:
848
849 // In the startSoftwareDownload we get the image size and the window size.
850 // We calculate how many DownloadSection we should receive and validate
851 // that we got the correct amount when we receive this message
852 success := true
853 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
854 onuLogger.WithFields(log.Fields{
855 "OnuId": o.ID,
856 "IntfId": o.PonPortID,
857 "OnuSn": o.Sn(),
858 "ExpectedSections": o.ImageSoftwareExpectedSections,
859 "ReceivedSections": o.ImageSoftwareReceivedSections,
860 }).Errorf("onu-did-not-receive-all-image-sections")
861 success = false
862 }
863
864 if success {
865 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(omciPkt, omciMsg, me.Success); errResp == nil {
866 o.MibDataSync++
867 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
868 onuLogger.WithFields(log.Fields{
869 "OnuId": o.ID,
870 "IntfId": o.PonPortID,
871 "OnuSn": o.Sn(),
872 "Err": err.Error(),
873 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
874 }
875 } else {
876 onuLogger.WithFields(log.Fields{
877 "OmciMsgType": omciMsg.MessageType,
878 "TransCorrId": omciMsg.TransactionID,
879 "Err": err.Error(),
880 "IntfId": o.PonPortID,
881 "SerialNumber": o.Sn(),
882 }).Error("error-while-processing-end-software-download-request")
883 }
884 } else {
885 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(omciPkt, omciMsg, me.ProcessingError); errResp == nil {
886 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
887 onuLogger.WithFields(log.Fields{
888 "OnuId": o.ID,
889 "IntfId": o.PonPortID,
890 "OnuSn": o.Sn(),
891 "Err": err.Error(),
892 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
893 }
894 }
895 }
896
897 case omci.ActivateSoftwareRequestType:
898 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(omciPkt, omciMsg); errResp == nil {
899 o.MibDataSync++
900 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
901 onuLogger.WithFields(log.Fields{
902 "OnuId": o.ID,
903 "IntfId": o.PonPortID,
904 "OnuSn": o.Sn(),
905 "Err": err.Error(),
906 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
907 }
908 if msgObj, err := omcilib.ParseActivateSoftwareRequest(omciPkt); err == nil {
909 o.ActiveImageEntityId = msgObj.EntityInstance
910 } else {
911 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
912 }
913 onuLogger.WithFields(log.Fields{
914 "OnuId": o.ID,
915 "IntfId": o.PonPortID,
916 "OnuSn": o.Sn(),
917 "ActiveImageEntityId": o.ActiveImageEntityId,
918 "CommittedImageEntityId": o.CommittedImageEntityId,
919 }).Info("onu-software-image-activated")
920
921 // powercycle the ONU
922 // we run this in a separate goroutine so that
923 // the ActivateSoftwareResponse is sent to VOLTHA
924 // NOTE do we need to wait before rebooting?
925 go func() {
926 if err := o.Reboot(10 * time.Second); err != nil {
927 log.WithFields(log.Fields{
928 "IntfId": o.PonPortID,
929 "OnuId": o.ID,
930 "SerialNumber": o.Sn(),
931 "err": err,
932 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
933 }
934 }()
935 }
936 case omci.CommitSoftwareRequestType:
937 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(omciPkt, omciMsg); errResp == nil {
938 o.MibDataSync++
939 if msgObj, err := omcilib.ParseCommitSoftwareRequest(omciPkt); err == nil {
940 // TODO validate that the image to commit is:
941 // - active
942 // - not already committed
943 o.CommittedImageEntityId = msgObj.EntityInstance
944 } else {
945 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
946 }
947 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
948 onuLogger.WithFields(log.Fields{
949 "OnuId": o.ID,
950 "IntfId": o.PonPortID,
951 "OnuSn": o.Sn(),
952 "Err": err.Error(),
953 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
954 }
955 onuLogger.WithFields(log.Fields{
956 "OnuId": o.ID,
957 "IntfId": o.PonPortID,
958 "OnuSn": o.Sn(),
959 "ActiveImageEntityId": o.ActiveImageEntityId,
960 "CommittedImageEntityId": o.CommittedImageEntityId,
961 }).Info("onu-software-image-committed")
962 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800963 default:
Matteo Scandolocedde462021-03-09 17:37:16 -0800964 onuLogger.WithFields(log.Fields{
965 "omciBytes": hex.EncodeToString(omciPkt.Data()),
966 "omciPkt": omciPkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800967 "omciMsgType": omciMsg.MessageType,
968 "transCorrId": omciMsg.TransactionID,
969 "IntfId": o.PonPortID,
970 "SerialNumber": o.Sn(),
971 }).Warnf("OMCI-message-not-supported")
972 }
973
974 if responsePkt != nil {
975 if err := o.sendOmciIndication(responsePkt, omciMsg.TransactionID, stream); err != nil {
976 onuLogger.WithFields(log.Fields{
977 "IntfId": o.PonPortID,
978 "SerialNumber": o.Sn(),
979 "omciPacket": responsePkt,
980 "omciMsgType": omciMsg.MessageType,
981 "transCorrId": omciMsg.TransactionID,
982 }).Errorf("failed-to-send-omci-message: %v", err)
983 }
984 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700985
Pragya Arya324337e2020-02-20 14:35:08 +0530986 o.publishOmciEvent(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800987}
Pragya Arya324337e2020-02-20 14:35:08 +0530988
Matteo Scandolof9d43412021-01-12 11:11:34 -0800989// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
990func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
991 indication := &openolt.Indication_OmciInd{
992 OmciInd: &openolt.OmciIndication{
993 IntfId: o.PonPortID,
994 OnuId: o.ID,
995 Pkt: responsePkt,
996 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700997 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800998 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
999 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001000 }
1001 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001002 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001003 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001004 "omciPacket": indication.OmciInd.Pkt,
1005 "transCorrId": txId,
1006 }).Trace("omci-message-sent")
1007 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001008}
1009
Matteo Scandolo27428702019-10-11 16:21:16 -07001010func (o *Onu) storePortNumber(portNo uint32) {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001011 // NOTE this needed only as long as we don't support multiple UNIs
Matteo Scandolo27428702019-10-11 16:21:16 -07001012 // we need to add support for multiple UNIs
1013 // the action plan is:
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001014 // - refactor the omcisim-sim library to use https://github.com/cboling/omci instead of canned messages
Matteo Scandolo27428702019-10-11 16:21:16 -07001015 // - change the library so that it reports a single UNI and remove this workaroung
1016 // - add support for multiple UNIs in BBSim
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001017 if o.PortNo == 0 || portNo < o.PortNo {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001018 onuLogger.WithFields(log.Fields{
1019 "IntfId": o.PonPortID,
1020 "OnuId": o.ID,
1021 "SerialNumber": o.Sn(),
1022 "OnuPortNo": o.PortNo,
1023 "FlowPortNo": portNo,
1024 }).Debug("Storing ONU portNo")
Matteo Scandolo27428702019-10-11 16:21:16 -07001025 o.PortNo = portNo
1026 }
1027}
1028
William Kurkian0418bc82019-11-06 12:16:24 -05001029func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001030 onuLogger.WithFields(log.Fields{
1031 "IntfId": o.PonPortID,
1032 "OnuId": id,
1033 "SerialNumber": o.Sn(),
1034 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001035 o.ID = id
1036}
1037
Matteo Scandolof9d43412021-01-12 11:11:34 -08001038func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001039 onuLogger.WithFields(log.Fields{
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001040 "Cookie": msg.Flow.Cookie,
1041 "DstPort": msg.Flow.Classifier.DstPort,
1042 "FlowId": msg.Flow.FlowId,
1043 "FlowType": msg.Flow.FlowType,
1044 "GemportId": msg.Flow.GemportId,
1045 "InnerVlan": msg.Flow.Classifier.IVid,
1046 "IntfId": msg.Flow.AccessIntfId,
1047 "IpProto": msg.Flow.Classifier.IpProto,
1048 "OnuId": msg.Flow.OnuId,
1049 "OnuSn": o.Sn(),
1050 "OuterVlan": msg.Flow.Classifier.OVid,
1051 "PortNo": msg.Flow.PortNo,
1052 "SrcPort": msg.Flow.Classifier.SrcPort,
1053 "UniID": msg.Flow.UniId,
1054 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1055 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1056 "ClassifierIVid": msg.Flow.Classifier.IVid,
1057 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001058 "ReplicateFlow": msg.Flow.ReplicateFlow,
1059 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001060 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001061
Matteo Scandolo813402b2019-10-23 19:24:52 -07001062 if msg.Flow.UniId != 0 {
1063 // as of now BBSim only support a single UNI, so ignore everything that is not targeted to it
1064 onuLogger.WithFields(log.Fields{
1065 "IntfId": o.PonPortID,
1066 "OnuId": o.ID,
1067 "SerialNumber": o.Sn(),
1068 }).Debug("Ignoring flow as it's not for the first UNI")
1069 return
1070 }
1071
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001072 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001073
1074 var gemPortId uint32
1075 if msg.Flow.ReplicateFlow {
1076 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1077 // first available gemport (we only need to send one packet)
1078 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1079 gemPortId = msg.Flow.PbitToGemport[0]
1080 } else {
1081 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1082 gemPortId = uint32(msg.Flow.GemportId)
1083 }
1084 o.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001085
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001086 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo27428702019-10-11 16:21:16 -07001087 // NOTE storing the PortNO, it's needed when sending PacketIndications
Matteo Scandolo813402b2019-10-23 19:24:52 -07001088 o.storePortNumber(uint32(msg.Flow.PortNo))
Matteo Scandolo4a036262020-08-17 15:56:13 -07001089
1090 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001091 s.HandleAuth()
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001092 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001093 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1094 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001095 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo99f18462019-10-28 14:14:28 -07001096
Matteo Scandolo4a036262020-08-17 15:56:13 -07001097 for _, s := range o.Services {
Matteo Scandolobd875b32020-09-18 17:46:31 -07001098 s.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001099 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001100 }
1101}
1102
Matteo Scandolof9d43412021-01-12 11:11:34 -08001103func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001104 onuLogger.WithFields(log.Fields{
1105 "IntfId": o.PonPortID,
1106 "OnuId": o.ID,
1107 "SerialNumber": o.Sn(),
1108 "FlowId": msg.Flow.FlowId,
1109 "FlowType": msg.Flow.FlowType,
1110 }).Debug("ONU receives FlowRemove")
1111
1112 for idx, flow := range o.FlowIds {
1113 // If the gemport is found, delete it from local cache.
1114 if flow == msg.Flow.FlowId {
1115 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1116 break
1117 }
1118 }
1119
1120 if len(o.FlowIds) == 0 {
1121 onuLogger.WithFields(log.Fields{
1122 "IntfId": o.PonPortID,
1123 "OnuId": o.ID,
1124 "SerialNumber": o.Sn(),
1125 }).Info("Resetting GemPort")
1126 o.GemPortAdded = false
1127
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301128 // check if ONU delete is performed and
1129 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001130 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301131 close(o.Channel)
1132 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001133 }
1134}
1135
Matteo Scandolocedde462021-03-09 17:37:16 -08001136func (o *Onu) Reboot(timeout time.Duration) error {
1137 onuLogger.WithFields(log.Fields{
1138 "IntfId": o.PonPortID,
1139 "OnuId": o.ID,
1140 "SerialNumber": o.Sn(),
1141 }).Debug("shutting-down-onu")
1142 if err := o.HandleShutdownONU(); err != nil {
1143 return err
1144 }
1145 time.Sleep(timeout)
1146 onuLogger.WithFields(log.Fields{
1147 "IntfId": o.PonPortID,
1148 "OnuId": o.ID,
1149 "SerialNumber": o.Sn(),
1150 }).Debug("power-on-onu")
1151 if err := o.HandlePowerOnONU(); err != nil {
1152 return err
1153 }
1154 return nil
1155}
1156
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001157// BBR methods
1158
1159func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1160 omciMsg := openolt.OmciMsg{
1161 IntfId: intfId,
1162 OnuId: onuId,
1163 Pkt: pktBytes,
1164 }
1165
1166 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1167 log.WithFields(log.Fields{
1168 "IntfId": intfId,
1169 "OnuId": onuId,
1170 "SerialNumber": common.OnuSnToString(sn),
1171 "Pkt": omciMsg.Pkt,
1172 }).Fatalf("Failed to send MIB Reset")
1173 }
1174 log.WithFields(log.Fields{
1175 "IntfId": intfId,
1176 "OnuId": onuId,
1177 "SerialNumber": common.OnuSnToString(sn),
1178 "Pkt": omciMsg.Pkt,
1179 }).Tracef("Sent OMCI message %s", msgType)
1180}
1181
1182func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1183 var next uint16
1184 if len(highPriority) > 0 && highPriority[0] {
1185 next = onu.hpTid
1186 onu.hpTid += 1
1187 if onu.hpTid < 0x8000 {
1188 onu.hpTid = 0x8000
1189 }
1190 } else {
1191 next = onu.tid
1192 onu.tid += 1
1193 if onu.tid >= 0x8000 {
1194 onu.tid = 1
1195 }
1196 }
1197 return next
1198}
1199
1200// TODO move this method in responders/omcisim
1201func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1202 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1203 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1204}
1205
Matteo Scandolof9d43412021-01-12 11:11:34 -08001206// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1207func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1208
1209 // we need to encode the packet in HEX
1210 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1211 hex.Encode(pkt, msg.OmciInd.Pkt)
1212 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1213 if err != nil {
1214 log.WithFields(log.Fields{
1215 "IntfId": o.PonPortID,
1216 "SerialNumber": o.Sn(),
1217 "omciPacket": msg.OmciInd.Pkt,
1218 }).Error("BBR Cannot parse OMCI packet")
1219 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001220
1221 log.WithFields(log.Fields{
1222 "IntfId": msg.OmciInd.IntfId,
1223 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001224 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001225 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001226 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301227 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001228 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001229 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001230 log.WithFields(log.Fields{
1231 "IntfId": msg.OmciInd.IntfId,
1232 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001233 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001234 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001235 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001236 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001237 case omci.MibResetResponseType:
1238 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1239 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1240 case omci.MibUploadResponseType:
1241 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1242 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1243 case omci.MibUploadNextResponseType:
1244 o.seqNumber++
1245
1246 if o.seqNumber > 290 {
1247 // NOTE we are done with the MIB Upload (290 is the number of messages the omci-sim library will respond to)
1248 galEnet, _ := omcilib.CreateGalEnetRequest(o.getNextTid(false))
1249 sendOmciMsg(galEnet, o.PonPortID, o.ID, o.SerialNumber, "CreateGalEnetRequest", client)
1250 } else {
1251 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1252 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1253 }
1254 case omci.CreateResponseType:
1255 // NOTE Creating a GemPort,
1256 // BBsim actually doesn't care about the values, so we can do we want with the parameters
1257 // In the same way we can create a GemPort even without setting up UNIs/TConts/...
1258 // but we need the GemPort to trigger the state change
1259
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001260 if !o.GemPortAdded {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001261 // NOTE this sends a CreateRequestType and BBSim replies with a CreateResponseType
1262 // thus we send this request only once
1263 gemReq, _ := omcilib.CreateGemPortRequest(o.getNextTid(false))
1264 sendOmciMsg(gemReq, o.PonPortID, o.ID, o.SerialNumber, "CreateGemPortRequest", client)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001265 o.GemPortAdded = true
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001266 } else {
Matteo Scandolocedde462021-03-09 17:37:16 -08001267 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001268 onuLogger.WithFields(log.Fields{
1269 "OnuId": o.ID,
1270 "IntfId": o.PonPortID,
1271 "OnuSn": o.Sn(),
1272 }).Errorf("Error while transitioning ONU State %v", err)
1273 }
1274 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001275 }
1276}
1277
1278func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1279
1280 classifierProto := openolt.Classifier{
1281 EthType: uint32(layers.EthernetTypeEAPOL),
1282 OVid: 4091,
1283 }
1284
1285 actionProto := openolt.Action{}
1286
1287 downstreamFlow := openolt.Flow{
1288 AccessIntfId: int32(o.PonPortID),
1289 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001290 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001291 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001292 FlowType: "downstream",
1293 AllocId: int32(0),
1294 NetworkIntfId: int32(0),
1295 GemportId: int32(1), // FIXME use the same value as CreateGemPortRequest PortID, do not hardcode
1296 Classifier: &classifierProto,
1297 Action: &actionProto,
1298 Priority: int32(100),
1299 Cookie: uint64(o.ID),
1300 PortNo: uint32(o.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
1301 }
1302
1303 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1304 log.WithFields(log.Fields{
1305 "IntfId": o.PonPortID,
1306 "OnuId": o.ID,
1307 "FlowId": downstreamFlow.FlowId,
1308 "PortNo": downstreamFlow.PortNo,
1309 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001310 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001311 }
1312 log.WithFields(log.Fields{
1313 "IntfId": o.PonPortID,
1314 "OnuId": o.ID,
1315 "FlowId": downstreamFlow.FlowId,
1316 "PortNo": downstreamFlow.PortNo,
1317 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1318 }).Info("Sent EAPOL Flow")
1319}
1320
1321func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001322
1323 // BBR only works with a single service (ATT HSIA)
1324 hsia := o.Services[0].(*Service)
1325
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001326 classifierProto := openolt.Classifier{
1327 EthType: uint32(layers.EthernetTypeIPv4),
1328 SrcPort: uint32(68),
1329 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001330 OVid: uint32(hsia.CTag),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001331 }
1332
1333 actionProto := openolt.Action{}
1334
1335 downstreamFlow := openolt.Flow{
1336 AccessIntfId: int32(o.PonPortID),
1337 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001338 UniId: int32(0), // FIXME do not hardcode this
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001339 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001340 FlowType: "downstream",
1341 AllocId: int32(0),
1342 NetworkIntfId: int32(0),
1343 GemportId: int32(1), // FIXME use the same value as CreateGemPortRequest PortID, do not hardcode
1344 Classifier: &classifierProto,
1345 Action: &actionProto,
1346 Priority: int32(100),
1347 Cookie: uint64(o.ID),
1348 PortNo: uint32(o.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
1349 }
1350
1351 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1352 log.WithFields(log.Fields{
1353 "IntfId": o.PonPortID,
1354 "OnuId": o.ID,
1355 "FlowId": downstreamFlow.FlowId,
1356 "PortNo": downstreamFlow.PortNo,
1357 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1358 }).Fatalf("Failed to send DHCP Flow")
1359 }
1360 log.WithFields(log.Fields{
1361 "IntfId": o.PonPortID,
1362 "OnuId": o.ID,
1363 "FlowId": downstreamFlow.FlowId,
1364 "PortNo": downstreamFlow.PortNo,
1365 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1366 }).Info("Sent DHCP Flow")
1367}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301368
1369// DeleteFlow method search and delete flowKey from the onu flows slice
1370func (onu *Onu) DeleteFlow(key FlowKey) {
1371 for pos, flowKey := range onu.Flows {
1372 if flowKey == key {
1373 // delete the flowKey by shifting all flowKeys by one
1374 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1375 t := make([]FlowKey, len(onu.Flows))
1376 copy(t, onu.Flows)
1377 onu.Flows = t
1378 break
1379 }
1380 }
1381}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301382
1383func (onu *Onu) ReDiscoverOnu() {
1384 // Wait for few seconds to be sure of the cleanup
1385 time.Sleep(5 * time.Second)
1386
1387 onuLogger.WithFields(log.Fields{
1388 "IntfId": onu.PonPortID,
1389 "OnuId": onu.ID,
1390 "OnuSn": onu.Sn(),
1391 }).Debug("Send ONU Re-Discovery")
1392
1393 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001394 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301395 log.WithFields(log.Fields{
1396 "IntfId": onu.PonPortID,
1397 "OnuSn": onu.Sn(),
1398 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001399 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301400 }
1401
Matteo Scandolocedde462021-03-09 17:37:16 -08001402 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301403 log.WithFields(log.Fields{
1404 "IntfId": onu.PonPortID,
1405 "OnuSn": onu.Sn(),
1406 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001407 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301408 }
1409}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001410
1411func (onu *Onu) addGemPortToService(gemport uint32, ethType uint32, oVlan uint32, iVlan uint32) {
1412 for _, s := range onu.Services {
1413 if service, ok := s.(*Service); ok {
1414 // EAPOL is a strange case, as packets are untagged
1415 // but we assume we will have a single service requiring EAPOL
1416 if ethType == uint32(layers.EthernetTypeEAPOL) && service.NeedsEapol {
1417 service.GemPort = gemport
1418 }
1419
1420 // For DHCP services we single tag the outgoing packets,
1421 // thus the flow only contains the CTag and we can use that to match the service
1422 if ethType == uint32(layers.EthernetTypeIPv4) && service.NeedsDhcp && service.CTag == int(oVlan) {
1423 service.GemPort = gemport
1424 }
1425
1426 // for dataplane services match both C and S tags
1427 if service.CTag == int(iVlan) && service.STag == int(oVlan) {
1428 service.GemPort = gemport
1429 }
1430 }
1431 }
1432}
1433
1434func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
1435 for _, s := range onu.Services {
1436 service := s.(*Service)
1437 if service.HwAddress.String() == macAddress.String() {
1438 return service, nil
1439 }
1440 }
1441 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1442}