blob: 6c1b5b9e608b9e2f68f539d425dc18e907c46b82 [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"
Himani Chawla13b1ee02021-03-15 01:43:53 +053025 "sync"
26
Matteo Scandolo4a036262020-08-17 15:56:13 -070027 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
28 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
29 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080030 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
31 me "github.com/opencord/omci-lib-go/generated"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010032 "net"
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080033 "strconv"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010034 "time"
35
Matteo Scandolo3bc73742019-08-20 14:04:04 -070036 "github.com/google/gopacket/layers"
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070037 "github.com/jpillora/backoff"
Matteo Scandolo4747d292019-08-05 11:50:18 -070038 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070039 "github.com/opencord/bbsim/internal/common"
40 omcilib "github.com/opencord/bbsim/internal/common/omci"
Matteo Scandolof9d43412021-01-12 11:11:34 -080041 "github.com/opencord/omci-lib-go"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070042 "github.com/opencord/voltha-protos/v4/go/openolt"
43 "github.com/opencord/voltha-protos/v4/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070044 log "github.com/sirupsen/logrus"
45)
46
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070047var onuLogger = log.WithFields(log.Fields{
48 "module": "ONU",
49})
50
Matteo Scandolocedde462021-03-09 17:37:16 -080051const (
52 // ONU transitions
53 OnuTxInitialize = "initialize"
54 OnuTxDiscover = "discover"
55 OnuTxEnable = "enable"
56 OnuTxDisable = "disable"
57 OnuTxPonDisable = "pon_disable"
58 OnuTxStartImageDownload = "start_image_download"
59 OnuTxProgressImageDownload = "progress_image_download"
60 OnuTxCompleteImageDownload = "complete_image_download"
61 OnuTxFailImageDownload = "fail_image_download"
62 OnuTxActivateImage = "activate_image"
63 OnuTxCommitImage = "commit_image"
64
65 // ONU States
66 OnuStateCreated = "created"
67 OnuStateInitialized = "initialized"
68 OnuStateDiscovered = "discovered"
69 OnuStateEnabled = "enabled"
70 OnuStateDisabled = "disabled"
71 OnuStatePonDisabled = "pon_disabled"
72 OnuStateImageDownloadStarted = "image_download_started"
73 OnuStateImageDownloadInProgress = "image_download_in_progress"
74 OnuStateImageDownloadComplete = "image_download_completed"
75 OnuStateImageDownloadError = "image_download_error"
76 OnuStateImageActivated = "software_image_activated"
77 OnuStateImageCommitted = "software_image_committed"
78
79 // BBR ONU States and Transitions
80 BbrOnuTxSendEapolFlow = "send_eapol_flow"
81 BbrOnuStateEapolFlowSent = "eapol_flow_sent"
82 BbrOnuTxSendDhcpFlow = "send_dhcp_flow"
83 BbrOnuStateDhcpFlowSent = "dhcp_flow_sent"
84)
85
Pragya Arya8bdb4532020-03-02 17:08:09 +053086type FlowKey struct {
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070087 ID uint64
Pragya Arya8bdb4532020-03-02 17:08:09 +053088 Direction string
89}
90
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070091type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -080092 ID uint32
93 PonPortID uint32
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070094 PonPort *PonPort
Matteo Scandoloe811ae92019-12-10 17:50:14 -080095 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +053096 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
97 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandolo4a036262020-08-17 15:56:13 -070098
99 Services []ServiceIf
100
101 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800102 // ONU State
Matteo Scandolo27428702019-10-11 16:21:16 -0700103 // PortNo comes with flows and it's used when sending packetIndications,
104 // There is one PortNo per UNI Port, for now we're only storing the first one
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700105 // FIXME add support for multiple UNIs (each UNI has a different PortNo)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800106 PortNo uint32
107 Flows []FlowKey
108 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700109
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700110 OperState *fsm.FSM
111 SerialNumber *openolt.SerialNumber
112
Matteo Scandolof9d43412021-01-12 11:11:34 -0800113 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700114
115 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800116 MibDataSync uint8
117 ImageSoftwareExpectedSections int
118 ImageSoftwareReceivedSections int
119 ActiveImageEntityId uint16
120 CommittedImageEntityId uint16
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800121
122 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700123 tid uint16
124 hpTid uint16
125 seqNumber uint16
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700126
Anand S Katti09541352020-01-29 15:54:01 +0530127 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
128 TrafficSchedulers *tech_profile.TrafficSchedulers
Himani Chawla13b1ee02021-03-15 01:43:53 +0530129 onuAlarmsInfoLock sync.RWMutex
130 onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700131}
132
Matteo Scandolo99f18462019-10-28 14:14:28 -0700133func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700134 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700135}
136
Matteo Scandolo4a036262020-08-17 15:56:13 -0700137func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, isMock bool) *Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700138
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700139 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800140 ID: id,
141 PonPortID: pon.ID,
142 PonPort: pon,
143 PortNo: 0,
144 tid: 0x1,
145 hpTid: 0x8000,
146 seqNumber: 0,
147 DoneChannel: make(chan bool, 1),
148 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
149 Flows: []FlowKey{},
150 DiscoveryDelay: delay,
151 MibDataSync: 0,
152 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
153 ImageSoftwareReceivedSections: 0,
154 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
155 CommittedImageEntityId: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700156 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800157 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700158 // NOTE this state machine is used to track the operational
159 // state as requested by VOLTHA
160 o.OperState = getOperStateFSM(func(e *fsm.Event) {
161 onuLogger.WithFields(log.Fields{
162 "ID": o.ID,
163 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
164 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530165 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700166 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
167 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800168 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700169 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700170 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800171 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
172 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
173 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100174 // 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 -0800175 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530176 // 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 -0800177 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStatePonDisabled},
178 // Software Image Download related states
179 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError}, Dst: OnuStateImageDownloadStarted},
180 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
181 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
182 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
183 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
184 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700185 // BBR States
186 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800187 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
188 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700189 },
190 fsm.Callbacks{
191 "enter_state": func(e *fsm.Event) {
192 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700193 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100194 "enter_initialized": func(e *fsm.Event) {
195 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800196 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800197
Matteo Scandolocedde462021-03-09 17:37:16 -0800198 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800199 onuLogger.WithFields(log.Fields{
200 "OnuId": o.ID,
201 "IntfId": o.PonPortID,
202 "OnuSn": o.Sn(),
203 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
204 }
205
Pragya Arya1cbefa42020-01-13 12:15:29 +0530206 if !isMock {
207 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700208 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530209 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100210 },
211 "enter_discovered": func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800212 msg := bbsim.Message{
213 Type: bbsim.OnuDiscIndication,
214 Data: bbsim.OnuDiscIndicationMessage{
215 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100216 },
217 }
218 o.Channel <- msg
219 },
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700220 "enter_enabled": func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800221
222 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
223 onuLogger.WithFields(log.Fields{
224 "IntfId": o.PonPortID,
225 "OnuId": o.ID,
226 "SerialNumber": o.Sn(),
227 }).Errorf("received-omci-with-sn-%s", common.OnuSnToString(sn))
228 return
229 } else {
230 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
231 }
232
Matteo Scandolof9d43412021-01-12 11:11:34 -0800233 msg := bbsim.Message{
234 Type: bbsim.OnuIndication,
235 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700236 OnuSN: o.SerialNumber,
237 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800238 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700239 },
240 }
241 o.Channel <- msg
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700242
243 // Once the ONU is enabled start listening for packets
244 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700245 s.Initialize(o.PonPort.Olt.OpenoltStream)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700246 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700247 },
248 "enter_disabled": func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700249
250 // clean the ONU state
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700251 o.PortNo = 0
252 o.Flows = []FlowKey{}
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800253 o.PonPort.removeOnuId(o.ID)
254 o.PonPort.removeAllocId(o.SerialNumber)
255 o.PonPort.removeGemPortBySn(o.SerialNumber)
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700256
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700257 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800258 if err := o.OperState.Event("disable"); err != nil {
259 onuLogger.WithFields(log.Fields{
260 "OnuId": o.ID,
261 "IntfId": o.PonPortID,
262 "OnuSn": o.Sn(),
263 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
264 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700265 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800266 msg := bbsim.Message{
267 Type: bbsim.OnuIndication,
268 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700269 OnuSN: o.SerialNumber,
270 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800271 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700272 },
273 }
274 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530275
276 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100277 // terminate the ONU's ProcessOnuMessages Go routine
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530278 if len(o.FlowIds) == 0 {
279 close(o.Channel)
280 }
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700281
282 for _, s := range o.Services {
283 s.Disable()
284 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530285 o.onuAlarmsInfoLock.Lock()
286 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
287 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700288 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700289 // BBR states
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700290 "enter_eapol_flow_sent": func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800291 msg := bbsim.Message{
292 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700293 }
294 o.Channel <- msg
295 },
296 "enter_dhcp_flow_sent": func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800297 msg := bbsim.Message{
298 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700299 }
300 o.Channel <- msg
301 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700302 },
303 )
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100304
Matteo Scandolo27428702019-10-11 16:21:16 -0700305 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700306}
307
William Kurkian0418bc82019-11-06 12:16:24 -0500308func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700309 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700310 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700311 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700312 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700313 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
314}
315
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100316// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000317func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700318 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100319 "onuID": o.ID,
320 "onuSN": o.Sn(),
321 "ponPort": o.PonPortID,
322 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700323
David Bainbridge103cf022019-12-16 20:11:35 +0000324loop:
325 for {
326 select {
327 case <-ctx.Done():
328 onuLogger.WithFields(log.Fields{
329 "onuID": o.ID,
330 "onuSN": o.Sn(),
331 }).Tracef("ONU message handling canceled via context")
332 break loop
333 case message, ok := <-o.Channel:
334 if !ok || ctx.Err() != nil {
335 onuLogger.WithFields(log.Fields{
336 "onuID": o.ID,
337 "onuSN": o.Sn(),
338 }).Tracef("ONU message handling canceled via channel close")
339 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700340 }
David Bainbridge103cf022019-12-16 20:11:35 +0000341 onuLogger.WithFields(log.Fields{
342 "onuID": o.ID,
343 "onuSN": o.Sn(),
344 "messageType": message.Type,
345 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700346
David Bainbridge103cf022019-12-16 20:11:35 +0000347 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800348 case bbsim.OnuDiscIndication:
349 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000350 // 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 +0530351 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000352 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800353 case bbsim.OnuIndication:
354 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000355 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800356 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800357 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800358 msg, _ := message.Data.(bbsim.OmciMessage)
359 o.handleOmciRequest(msg, stream)
360 case bbsim.UniStatusAlarm:
361 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530362 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
363 MeInstance: msg.EntityID,
364 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
365 }
366 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
367 o.onuAlarmsInfoLock.Lock()
368 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
369 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
370 if pkt != nil { //pkt will be nil if we are unable to create the alarm
371 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
372 onuLogger.WithFields(log.Fields{
373 "IntfId": o.PonPortID,
374 "SerialNumber": o.Sn(),
375 "omciPacket": pkt,
376 "adminState": msg.AdminState,
377 "entityID": msg.EntityID,
378 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
379 alarmInfo.SequenceNo--
380 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800381 onuLogger.WithFields(log.Fields{
382 "IntfId": o.PonPortID,
383 "SerialNumber": o.Sn(),
384 "omciPacket": pkt,
385 "adminState": msg.AdminState,
386 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530387 }).Trace("UNI-Link-alarm-sent")
388 if alarmBitMap == [28]byte{0} {
389 delete(o.onuAlarmsInfo, onuAlarmMapKey)
390 } else {
391 alarmInfo.AlarmBitMap = alarmBitMap
392 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
393 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800394 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530395 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800396 case bbsim.FlowAdd:
397 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700398 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800399 case bbsim.FlowRemoved:
400 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700401 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800402 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700403
Matteo Scandolof9d43412021-01-12 11:11:34 -0800404 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000405
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700406 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000407 "IntfId": msg.IntfId,
408 "OnuId": msg.OnuId,
409 "pktType": msg.Type,
410 }).Trace("Received OnuPacketOut Message")
411
Matteo Scandolo618a6582020-09-09 12:21:29 -0700412 if msg.Type == packetHandlers.EAPOL || msg.Type == packetHandlers.DHCP {
413
414 service, err := o.findServiceByMacAddress(msg.MacAddress)
415 if err != nil {
416 onuLogger.WithFields(log.Fields{
417 "IntfId": msg.IntfId,
418 "OnuId": msg.OnuId,
419 "pktType": msg.Type,
420 "MacAddress": msg.MacAddress,
421 "Pkt": hex.EncodeToString(msg.Packet.Data()),
422 "OnuSn": o.Sn(),
423 }).Error("Cannot find Service associated with packet")
424 return
425 }
426 service.PacketCh <- msg
427 } else if msg.Type == packetHandlers.IGMP {
428 // if it's an IGMP packet we assume we have a single IGMP service
429 for _, s := range o.Services {
430 service := s.(*Service)
431
432 if service.NeedsIgmp {
433 service.PacketCh <- msg
434 }
435 }
David Bainbridge103cf022019-12-16 20:11:35 +0000436 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700437
Matteo Scandolof9d43412021-01-12 11:11:34 -0800438 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000439 // NOTE we only receive BBR packets here.
440 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
441 // 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 -0800442 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000443
444 log.WithFields(log.Fields{
445 "IntfId": msg.IntfId,
446 "OnuId": msg.OnuId,
447 "pktType": msg.Type,
448 }).Trace("Received OnuPacketIn Message")
449
450 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700451 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 +0000452 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700453 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000454 }
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700455 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800456 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800457 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800458 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
459 o.handleOmciResponse(msg, client)
460 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000461 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800462 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000463 o.sendDhcpFlow(client)
464 default:
465 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700466 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700467 }
468 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100469 onuLogger.WithFields(log.Fields{
470 "onuID": o.ID,
471 "onuSN": o.Sn(),
472 }).Debug("Stopped handling ONU Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700473}
474
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800475func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700476 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700477 sn.VendorId = []byte("BBSM")
478 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700479 return sn
480}
481
Matteo Scandolof9d43412021-01-12 11:11:34 -0800482func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700483 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800484 IntfId: o.PonPortID,
485 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700486 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700487
Matteo Scandolo4747d292019-08-05 11:50:18 -0700488 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700489 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700490 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700491 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700492
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700493 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800494 "IntfId": o.PonPortID,
495 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700496 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700497 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800498 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800499
500 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
501 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800502 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800503 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800504 o.sendOnuDiscIndication(msg, stream)
505 }
506 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700507}
508
Matteo Scandolof9d43412021-01-12 11:11:34 -0800509func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800510 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
511 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700512
513 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700514 IntfId: o.PonPortID,
515 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700516 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700517 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700518 SerialNumber: o.SerialNumber,
519 }}
520 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800521 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700522 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700523 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700524 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700525 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800526 "IntfId": o.PonPortID,
527 "OnuId": o.ID,
528 "VolthaOnuId": msg.OnuID,
529 "OperState": msg.OperState.String(),
530 "AdminState": msg.OperState.String(),
531 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700532 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700533
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700534}
535
Matteo Scandolof9d43412021-01-12 11:11:34 -0800536func (o *Onu) HandleShutdownONU() error {
537
538 dyingGasp := pb.ONUAlarmRequest{
539 AlarmType: "DYING_GASP",
540 SerialNumber: o.Sn(),
541 Status: "on",
542 }
543
544 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
545 onuLogger.WithFields(log.Fields{
546 "OnuId": o.ID,
547 "IntfId": o.PonPortID,
548 "OnuSn": o.Sn(),
549 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
550 return err
551 }
552
553 losReq := pb.ONUAlarmRequest{
554 AlarmType: "ONU_ALARM_LOS",
555 SerialNumber: o.Sn(),
556 Status: "on",
557 }
558
559 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
560 onuLogger.WithFields(log.Fields{
561 "OnuId": o.ID,
562 "IntfId": o.PonPortID,
563 "OnuSn": o.Sn(),
564 }).Errorf("Cannot send LOS: %s", err.Error())
565
566 return err
567 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530568 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800569 // TODO if it's the last ONU on the PON, then send a PON LOS
570
Matteo Scandolocedde462021-03-09 17:37:16 -0800571 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800572 onuLogger.WithFields(log.Fields{
573 "OnuId": o.ID,
574 "IntfId": o.PonPortID,
575 "OnuSn": o.Sn(),
576 }).Errorf("Cannot shutdown ONU: %s", err.Error())
577 return err
578 }
579
580 return nil
581}
582
583func (o *Onu) HandlePowerOnONU() error {
584 intitalState := o.InternalState.Current()
585
586 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800587 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
588 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800589 onuLogger.WithFields(log.Fields{
590 "OnuId": o.ID,
591 "IntfId": o.PonPortID,
592 "OnuSn": o.Sn(),
593 }).Errorf("Cannot poweron ONU: %s", err.Error())
594 return err
595 }
596 }
597
598 // turn off the LOS Alarm
599 losReq := pb.ONUAlarmRequest{
600 AlarmType: "ONU_ALARM_LOS",
601 SerialNumber: o.Sn(),
602 Status: "off",
603 }
604
605 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
606 onuLogger.WithFields(log.Fields{
607 "OnuId": o.ID,
608 "IntfId": o.PonPortID,
609 "OnuSn": o.Sn(),
610 }).Errorf("Cannot send LOS: %s", err.Error())
611 return err
612 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530613 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800614
615 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800616 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800617 onuLogger.WithFields(log.Fields{
618 "OnuId": o.ID,
619 "IntfId": o.PonPortID,
620 "OnuSn": o.Sn(),
621 }).Errorf("Cannot poweron ONU: %s", err.Error())
622 return err
623 }
624
625 // move o directly to enable state only when its a powercycle case
626 // in case of first time o poweron o will be moved to enable on
627 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800628 if intitalState == OnuStateDisabled {
629 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800630 onuLogger.WithFields(log.Fields{
631 "OnuId": o.ID,
632 "IntfId": o.PonPortID,
633 "OnuSn": o.Sn(),
634 }).Errorf("Cannot enable ONU: %s", err.Error())
635 return err
636 }
637 }
638
639 return nil
640}
641
642func (o *Onu) SetAlarm(alarmType string, status string) error {
643 alarmReq := pb.ONUAlarmRequest{
644 AlarmType: alarmType,
645 SerialNumber: o.Sn(),
646 Status: status,
647 }
648
649 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
650 if err != nil {
651 return err
652 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530653 raiseAlarm := false
654 if alarmReq.Status == "on" {
655 raiseAlarm = true
656 }
657 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800658 return nil
659}
660
661func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530662 if olt.PublishEvents {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800663 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
Pragya Arya324337e2020-02-20 14:35:08 +0530664 if err != nil {
665 log.Errorf("error in getting msgType %v", err)
666 return
667 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800668 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530669 o.seqNumber = 0
670 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800671 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530672 o.seqNumber++
673 if o.seqNumber > 290 {
674 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
675 }
676 }
677 }
678}
679
Scott Bakerb90c4312020-03-12 21:33:25 -0700680// Create a TestResponse packet and send it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800681func (o *Onu) sendTestResult(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
682 resp, err := omcilib.BuildTestResult(msg.OmciMsg.Pkt)
Scott Bakerb90c4312020-03-12 21:33:25 -0700683 if err != nil {
684 return err
685 }
686
687 var omciInd openolt.OmciIndication
688 omciInd.IntfId = o.PonPortID
689 omciInd.OnuId = o.ID
690 omciInd.Pkt = resp
691
692 omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
693 if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
Scott Bakerb90c4312020-03-12 21:33:25 -0700694 return err
695 }
696 onuLogger.WithFields(log.Fields{
697 "IntfId": o.PonPortID,
698 "SerialNumber": o.Sn(),
699 "omciPacket": omciInd.Pkt,
700 }).Tracef("Sent TestResult OMCI message")
701
702 return nil
703}
704
Matteo Scandolof9d43412021-01-12 11:11:34 -0800705// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
706// and generate the appropriate response to it
707func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
708
709 omciPkt, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciMsg.Pkt)
710 if err != nil {
711 log.WithFields(log.Fields{
712 "IntfId": o.PonPortID,
713 "SerialNumber": o.Sn(),
Matteo Scandolocedde462021-03-09 17:37:16 -0800714 "omciPacket": omcilib.HexDecode(msg.OmciMsg.Pkt),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800715 }).Error("cannot-parse-OMCI-packet")
716 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700717
718 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800719 "omciMsgType": omciMsg.MessageType,
720 "transCorrId": strconv.FormatInt(int64(omciMsg.TransactionID), 16),
721 "DeviceIdent": omciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700722 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700723 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800724 }).Trace("omci-message-decoded")
725
726 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800727 var errResp error
Matteo Scandolof9d43412021-01-12 11:11:34 -0800728 switch omciMsg.MessageType {
729 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800730 onuLogger.WithFields(log.Fields{
731 "IntfId": o.PonPortID,
732 "OnuId": o.ID,
733 "SerialNumber": o.Sn(),
734 }).Debug("received-mib-reset-request-resetting-mds")
Girish Gowdrae2683102021-03-05 08:24:26 -0800735 if responsePkt, errResp = omcilib.CreateMibResetResponse(omciMsg.TransactionID); errResp == nil {
736 o.MibDataSync = 0
737 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800738 case omci.MibUploadRequestType:
739 responsePkt, _ = omcilib.CreateMibUploadResponse(omciMsg.TransactionID)
740 case omci.MibUploadNextRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800741 responsePkt, _ = omcilib.CreateMibUploadNextResponse(omciPkt, omciMsg, o.MibDataSync)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800742 case omci.GetRequestType:
Matteo Scandolocedde462021-03-09 17:37:16 -0800743 responsePkt, _ = omcilib.CreateGetResponse(omciPkt, omciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId, o.CommittedImageEntityId)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800744 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800745 success := true
Matteo Scandolof9d43412021-01-12 11:11:34 -0800746 msgObj, _ := omcilib.ParseSetRequest(omciPkt)
747 switch msgObj.EntityClass {
748 case me.PhysicalPathTerminationPointEthernetUniClassID:
749 // if we're Setting a PPTP state
750 // we need to send the appropriate alarm
751
752 if msgObj.EntityInstance == 257 {
753 // for now we're only caring about the first UNI
754 // NOTE that the EntityID for the UNI port is for now hardcoded in
755 // omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
756 // are reported during the MIB Upload sequence
757 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530758 raiseOMCIAlarm := false
759 if adminState == 1 {
760 raiseOMCIAlarm = true
761 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800762 msg := bbsim.Message{
763 Type: bbsim.UniStatusAlarm,
764 Data: bbsim.UniStatusAlarmMessage{
Himani Chawla13b1ee02021-03-15 01:43:53 +0530765 OnuSN: o.SerialNumber,
766 OnuID: o.ID,
767 AdminState: adminState,
768 EntityID: msgObj.EntityInstance,
769 RaiseOMCIAlarm: raiseOMCIAlarm,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800770 },
771 }
772 o.Channel <- msg
773 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800774 case me.TContClassID:
775 allocId := msgObj.Attributes["AllocId"].(uint16)
776
777 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
778 // otherwise we are adding it
779 if allocId == 255 || allocId == 65535 {
780 onuLogger.WithFields(log.Fields{
781 "IntfId": o.PonPortID,
782 "OnuId": o.ID,
783 "TContId": msgObj.EntityInstance,
784 "AllocId": allocId,
785 "SerialNumber": o.Sn(),
786 }).Trace("freeing-alloc-id-via-omci")
787 o.PonPort.removeAllocId(o.SerialNumber)
788 } else {
789 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
790 onuLogger.WithFields(log.Fields{
791 "IntfId": o.PonPortID,
792 "OnuId": o.ID,
793 "AllocId": allocId,
794 "SerialNumber": o.Sn(),
795 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
796 success = false
797 } else {
798 onuLogger.WithFields(log.Fields{
799 "IntfId": o.PonPortID,
800 "OnuId": o.ID,
801 "TContId": msgObj.EntityInstance,
802 "AllocId": allocId,
803 "SerialNumber": o.Sn(),
804 }).Trace("storing-alloc-id-via-omci")
805 o.PonPort.storeAllocId(allocId, o.SerialNumber)
806 }
807 }
808
809 }
810
811 if success {
812 if responsePkt, errResp = omcilib.CreateSetResponse(omciPkt, omciMsg, me.Success); errResp == nil {
813 o.MibDataSync++
814 }
815 } else {
816 responsePkt, _ = omcilib.CreateSetResponse(omciPkt, omciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800817 }
818 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800819 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
820 var used bool
821 var sn *openolt.SerialNumber
822 msgObj, err := omcilib.ParseCreateRequest(omciPkt)
823 if err == nil {
824 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
825 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
826 onuLogger.WithFields(log.Fields{
827 "IntfId": o.PonPortID,
828 "OnuId": o.ID,
829 "GemPortId": msgObj.EntityInstance,
830 "SerialNumber": o.Sn(),
831 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
832 } else {
833 onuLogger.WithFields(log.Fields{
834 "IntfId": o.PonPortID,
835 "OnuId": o.ID,
836 "GemPortId": msgObj.EntityInstance,
837 "SerialNumber": o.Sn(),
838 }).Trace("storing-gem-port-id-via-omci")
839 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
840 }
841 }
842 }
843
844 // if the gemPort is valid then increment the MDS and return a successful response
845 // otherwise fail the request
846 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
847 // validation this check will need to be rewritten
848 if !used {
849 if responsePkt, errResp = omcilib.CreateCreateResponse(omciPkt, omciMsg, me.Success); errResp == nil {
850 o.MibDataSync++
851 }
852 } else {
853 responsePkt, _ = omcilib.CreateCreateResponse(omciPkt, omciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800854 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800855 case omci.DeleteRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800856 msgObj, err := omcilib.ParseDeleteRequest(omciPkt)
857 if err == nil {
858 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
859 onuLogger.WithFields(log.Fields{
860 "IntfId": o.PonPortID,
861 "OnuId": o.ID,
862 "GemPortId": msgObj.EntityInstance,
863 "SerialNumber": o.Sn(),
864 }).Trace("freeing-gem-port-id-via-omci")
865 o.PonPort.removeGemPort(msgObj.EntityInstance)
866 }
867 }
868
Girish Gowdrae2683102021-03-05 08:24:26 -0800869 if responsePkt, errResp = omcilib.CreateDeleteResponse(omciPkt, omciMsg); errResp == nil {
870 o.MibDataSync++
871 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800872 case omci.RebootRequestType:
873
874 responsePkt, _ = omcilib.CreateRebootResponse(omciPkt, omciMsg)
875
876 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800877 // we run this in a separate goroutine so that
878 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800879 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800880 if err := o.Reboot(10 * time.Second); err != nil {
881 log.WithFields(log.Fields{
882 "IntfId": o.PonPortID,
883 "OnuId": o.ID,
884 "SerialNumber": o.Sn(),
885 "err": err,
886 }).Error("cannot-reboot-onu-after-omci-reboot-request")
887 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800888 }()
889 case omci.TestRequestType:
890
891 // Test message is special, it requires sending two packets:
892 // first packet: TestResponse, says whether test was started successully, handled by omci-sim
893 // second packet, TestResult, reports the result of running the self-test
894 // TestResult can come some time after a TestResponse
895 // TODO: Implement some delay between the TestResponse and the TestResult
896 isTest, err := omcilib.IsTestRequest(msg.OmciMsg.Pkt)
897 if (err == nil) && (isTest) {
898 if sendErr := o.sendTestResult(msg, stream); sendErr != nil {
899 onuLogger.WithFields(log.Fields{
900 "IntfId": o.PonPortID,
Matteo Scandolocedde462021-03-09 17:37:16 -0800901 "OnuId": o.ID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800902 "SerialNumber": o.Sn(),
903 "omciPacket": msg.OmciMsg.Pkt,
904 "msg": msg,
905 "err": sendErr,
906 }).Error("send-TestResult-indication-failed")
907 }
908 }
Girish Gowdraa539f522021-02-15 23:00:45 -0800909 case omci.SynchronizeTimeRequestType:
910 // MDS counter increment is not required for this message type
911 responsePkt, _ = omcilib.CreateSyncTimeResponse(omciPkt, omciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -0800912 case omci.StartSoftwareDownloadRequestType:
913
914 o.ImageSoftwareReceivedSections = 0
915
916 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(omciPkt)
917
918 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(omciPkt, omciMsg); errResp == nil {
919 o.MibDataSync++
920 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
921 onuLogger.WithFields(log.Fields{
922 "OnuId": o.ID,
923 "IntfId": o.PonPortID,
924 "OnuSn": o.Sn(),
925 "Err": err.Error(),
926 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
927 }
928 } else {
929 onuLogger.WithFields(log.Fields{
930 "OmciMsgType": omciMsg.MessageType,
931 "TransCorrId": omciMsg.TransactionID,
932 "Err": err.Error(),
933 "IntfId": o.PonPortID,
934 "SerialNumber": o.Sn(),
935 }).Error("error-while-processing-start-software-download-request")
936 }
937 case omci.DownloadSectionRequestType:
938 if msgObj, err := omcilib.ParseDownloadSectionRequest(omciPkt); err == nil {
939 onuLogger.WithFields(log.Fields{
940 "OmciMsgType": omciMsg.MessageType,
941 "TransCorrId": omciMsg.TransactionID,
942 "EntityInstance": msgObj.EntityInstance,
943 "SectionNumber": msgObj.SectionNumber,
944 "SectionData": msgObj.SectionData,
945 }).Trace("received-download-section-request")
946 o.ImageSoftwareReceivedSections++
947 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
948 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
949 onuLogger.WithFields(log.Fields{
950 "OnuId": o.ID,
951 "IntfId": o.PonPortID,
952 "OnuSn": o.Sn(),
953 "Err": err.Error(),
954 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
955 }
956 }
957 }
958 case omci.DownloadSectionRequestWithResponseType:
959 // NOTE we only need to respond if an ACK is requested
960 responsePkt, err = omcilib.CreateDownloadSectionResponse(omciPkt, omciMsg)
961 if err != nil {
962 onuLogger.WithFields(log.Fields{
963 "OmciMsgType": omciMsg.MessageType,
964 "TransCorrId": omciMsg.TransactionID,
965 "Err": err.Error(),
966 "IntfId": o.PonPortID,
967 "SerialNumber": o.Sn(),
968 }).Error("error-while-processing-create-download-section-response")
969 return
970 }
971 o.ImageSoftwareReceivedSections++
972
973 case omci.EndSoftwareDownloadRequestType:
974
975 // In the startSoftwareDownload we get the image size and the window size.
976 // We calculate how many DownloadSection we should receive and validate
977 // that we got the correct amount when we receive this message
978 success := true
979 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
980 onuLogger.WithFields(log.Fields{
981 "OnuId": o.ID,
982 "IntfId": o.PonPortID,
983 "OnuSn": o.Sn(),
984 "ExpectedSections": o.ImageSoftwareExpectedSections,
985 "ReceivedSections": o.ImageSoftwareReceivedSections,
986 }).Errorf("onu-did-not-receive-all-image-sections")
987 success = false
988 }
989
990 if success {
991 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(omciPkt, omciMsg, me.Success); errResp == nil {
992 o.MibDataSync++
993 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
994 onuLogger.WithFields(log.Fields{
995 "OnuId": o.ID,
996 "IntfId": o.PonPortID,
997 "OnuSn": o.Sn(),
998 "Err": err.Error(),
999 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1000 }
1001 } else {
1002 onuLogger.WithFields(log.Fields{
1003 "OmciMsgType": omciMsg.MessageType,
1004 "TransCorrId": omciMsg.TransactionID,
1005 "Err": err.Error(),
1006 "IntfId": o.PonPortID,
1007 "SerialNumber": o.Sn(),
1008 }).Error("error-while-processing-end-software-download-request")
1009 }
1010 } else {
1011 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(omciPkt, omciMsg, me.ProcessingError); errResp == nil {
1012 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1013 onuLogger.WithFields(log.Fields{
1014 "OnuId": o.ID,
1015 "IntfId": o.PonPortID,
1016 "OnuSn": o.Sn(),
1017 "Err": err.Error(),
1018 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1019 }
1020 }
1021 }
1022
1023 case omci.ActivateSoftwareRequestType:
1024 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(omciPkt, omciMsg); errResp == nil {
1025 o.MibDataSync++
1026 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1027 onuLogger.WithFields(log.Fields{
1028 "OnuId": o.ID,
1029 "IntfId": o.PonPortID,
1030 "OnuSn": o.Sn(),
1031 "Err": err.Error(),
1032 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1033 }
1034 if msgObj, err := omcilib.ParseActivateSoftwareRequest(omciPkt); err == nil {
1035 o.ActiveImageEntityId = msgObj.EntityInstance
1036 } else {
1037 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1038 }
1039 onuLogger.WithFields(log.Fields{
1040 "OnuId": o.ID,
1041 "IntfId": o.PonPortID,
1042 "OnuSn": o.Sn(),
1043 "ActiveImageEntityId": o.ActiveImageEntityId,
1044 "CommittedImageEntityId": o.CommittedImageEntityId,
1045 }).Info("onu-software-image-activated")
1046
1047 // powercycle the ONU
1048 // we run this in a separate goroutine so that
1049 // the ActivateSoftwareResponse is sent to VOLTHA
1050 // NOTE do we need to wait before rebooting?
1051 go func() {
1052 if err := o.Reboot(10 * time.Second); err != nil {
1053 log.WithFields(log.Fields{
1054 "IntfId": o.PonPortID,
1055 "OnuId": o.ID,
1056 "SerialNumber": o.Sn(),
1057 "err": err,
1058 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1059 }
1060 }()
1061 }
1062 case omci.CommitSoftwareRequestType:
1063 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(omciPkt, omciMsg); errResp == nil {
1064 o.MibDataSync++
1065 if msgObj, err := omcilib.ParseCommitSoftwareRequest(omciPkt); err == nil {
1066 // TODO validate that the image to commit is:
1067 // - active
1068 // - not already committed
1069 o.CommittedImageEntityId = msgObj.EntityInstance
1070 } else {
1071 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1072 }
1073 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1074 onuLogger.WithFields(log.Fields{
1075 "OnuId": o.ID,
1076 "IntfId": o.PonPortID,
1077 "OnuSn": o.Sn(),
1078 "Err": err.Error(),
1079 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1080 }
1081 onuLogger.WithFields(log.Fields{
1082 "OnuId": o.ID,
1083 "IntfId": o.PonPortID,
1084 "OnuSn": o.Sn(),
1085 "ActiveImageEntityId": o.ActiveImageEntityId,
1086 "CommittedImageEntityId": o.CommittedImageEntityId,
1087 }).Info("onu-software-image-committed")
1088 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301089 case omci.GetAllAlarmsRequestType:
1090 // Reset the alarm sequence number on receiving get all alarms request.
1091 o.onuAlarmsInfoLock.Lock()
1092 for key, alarmInfo := range o.onuAlarmsInfo {
1093 // reset the alarm sequence no
1094 alarmInfo.SequenceNo = 0
1095 o.onuAlarmsInfo[key] = alarmInfo
1096 }
1097 o.onuAlarmsInfoLock.Unlock()
1098 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(omciMsg.TransactionID, o.onuAlarmsInfo)
1099 case omci.GetAllAlarmsNextRequestType:
1100 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(omciPkt, omciMsg, o.onuAlarmsInfo); errResp != nil {
1101 responsePkt = nil //Do not send any response for error case
1102 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001103 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001104 onuLogger.WithFields(log.Fields{
1105 "omciBytes": hex.EncodeToString(omciPkt.Data()),
1106 "omciPkt": omciPkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001107 "omciMsgType": omciMsg.MessageType,
1108 "transCorrId": omciMsg.TransactionID,
1109 "IntfId": o.PonPortID,
1110 "SerialNumber": o.Sn(),
1111 }).Warnf("OMCI-message-not-supported")
1112 }
1113
1114 if responsePkt != nil {
1115 if err := o.sendOmciIndication(responsePkt, omciMsg.TransactionID, stream); err != nil {
1116 onuLogger.WithFields(log.Fields{
1117 "IntfId": o.PonPortID,
1118 "SerialNumber": o.Sn(),
1119 "omciPacket": responsePkt,
1120 "omciMsgType": omciMsg.MessageType,
1121 "transCorrId": omciMsg.TransactionID,
1122 }).Errorf("failed-to-send-omci-message: %v", err)
1123 }
1124 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001125
Pragya Arya324337e2020-02-20 14:35:08 +05301126 o.publishOmciEvent(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -08001127}
Pragya Arya324337e2020-02-20 14:35:08 +05301128
Matteo Scandolof9d43412021-01-12 11:11:34 -08001129// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1130func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1131 indication := &openolt.Indication_OmciInd{
1132 OmciInd: &openolt.OmciIndication{
1133 IntfId: o.PonPortID,
1134 OnuId: o.ID,
1135 Pkt: responsePkt,
1136 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001137 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001138 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1139 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001140 }
1141 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001142 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001143 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001144 "omciPacket": indication.OmciInd.Pkt,
1145 "transCorrId": txId,
1146 }).Trace("omci-message-sent")
1147 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001148}
1149
Matteo Scandolo27428702019-10-11 16:21:16 -07001150func (o *Onu) storePortNumber(portNo uint32) {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001151 // NOTE this needed only as long as we don't support multiple UNIs
Matteo Scandolo27428702019-10-11 16:21:16 -07001152 // we need to add support for multiple UNIs
1153 // the action plan is:
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001154 // - refactor the omcisim-sim library to use https://github.com/cboling/omci instead of canned messages
Matteo Scandolo27428702019-10-11 16:21:16 -07001155 // - change the library so that it reports a single UNI and remove this workaroung
1156 // - add support for multiple UNIs in BBSim
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001157 if o.PortNo == 0 || portNo < o.PortNo {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001158 onuLogger.WithFields(log.Fields{
1159 "IntfId": o.PonPortID,
1160 "OnuId": o.ID,
1161 "SerialNumber": o.Sn(),
1162 "OnuPortNo": o.PortNo,
1163 "FlowPortNo": portNo,
1164 }).Debug("Storing ONU portNo")
Matteo Scandolo27428702019-10-11 16:21:16 -07001165 o.PortNo = portNo
1166 }
1167}
1168
William Kurkian0418bc82019-11-06 12:16:24 -05001169func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001170 onuLogger.WithFields(log.Fields{
1171 "IntfId": o.PonPortID,
1172 "OnuId": id,
1173 "SerialNumber": o.Sn(),
1174 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001175 o.ID = id
1176}
1177
Matteo Scandolof9d43412021-01-12 11:11:34 -08001178func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001179 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001180 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001181 "Cookie": msg.Flow.Cookie,
1182 "DstPort": msg.Flow.Classifier.DstPort,
1183 "FlowId": msg.Flow.FlowId,
1184 "FlowType": msg.Flow.FlowType,
1185 "GemportId": msg.Flow.GemportId,
1186 "InnerVlan": msg.Flow.Classifier.IVid,
1187 "IntfId": msg.Flow.AccessIntfId,
1188 "IpProto": msg.Flow.Classifier.IpProto,
1189 "OnuId": msg.Flow.OnuId,
1190 "OnuSn": o.Sn(),
1191 "OuterVlan": msg.Flow.Classifier.OVid,
1192 "PortNo": msg.Flow.PortNo,
1193 "SrcPort": msg.Flow.Classifier.SrcPort,
1194 "UniID": msg.Flow.UniId,
1195 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1196 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1197 "ClassifierIVid": msg.Flow.Classifier.IVid,
1198 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001199 "ReplicateFlow": msg.Flow.ReplicateFlow,
1200 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001201 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001202
Matteo Scandolo813402b2019-10-23 19:24:52 -07001203 if msg.Flow.UniId != 0 {
1204 // as of now BBSim only support a single UNI, so ignore everything that is not targeted to it
1205 onuLogger.WithFields(log.Fields{
1206 "IntfId": o.PonPortID,
1207 "OnuId": o.ID,
1208 "SerialNumber": o.Sn(),
1209 }).Debug("Ignoring flow as it's not for the first UNI")
1210 return
1211 }
1212
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001213 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001214
1215 var gemPortId uint32
1216 if msg.Flow.ReplicateFlow {
1217 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1218 // first available gemport (we only need to send one packet)
1219 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1220 gemPortId = msg.Flow.PbitToGemport[0]
1221 } else {
1222 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1223 gemPortId = uint32(msg.Flow.GemportId)
1224 }
1225 o.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001226
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001227 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo27428702019-10-11 16:21:16 -07001228 // NOTE storing the PortNO, it's needed when sending PacketIndications
Matteo Scandolo813402b2019-10-23 19:24:52 -07001229 o.storePortNumber(uint32(msg.Flow.PortNo))
Matteo Scandolo4a036262020-08-17 15:56:13 -07001230
1231 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001232 s.HandleAuth()
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001233 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001234 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1235 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001236 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo99f18462019-10-28 14:14:28 -07001237
Matteo Scandolo4a036262020-08-17 15:56:13 -07001238 for _, s := range o.Services {
Matteo Scandolobd875b32020-09-18 17:46:31 -07001239 s.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001240 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001241 }
1242}
1243
Matteo Scandolof9d43412021-01-12 11:11:34 -08001244func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001245 onuLogger.WithFields(log.Fields{
1246 "IntfId": o.PonPortID,
1247 "OnuId": o.ID,
1248 "SerialNumber": o.Sn(),
1249 "FlowId": msg.Flow.FlowId,
1250 "FlowType": msg.Flow.FlowType,
1251 }).Debug("ONU receives FlowRemove")
1252
1253 for idx, flow := range o.FlowIds {
1254 // If the gemport is found, delete it from local cache.
1255 if flow == msg.Flow.FlowId {
1256 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1257 break
1258 }
1259 }
1260
1261 if len(o.FlowIds) == 0 {
1262 onuLogger.WithFields(log.Fields{
1263 "IntfId": o.PonPortID,
1264 "OnuId": o.ID,
1265 "SerialNumber": o.Sn(),
1266 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001267
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301268 // check if ONU delete is performed and
1269 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001270 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301271 close(o.Channel)
1272 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001273 }
1274}
1275
Matteo Scandolocedde462021-03-09 17:37:16 -08001276func (o *Onu) Reboot(timeout time.Duration) error {
1277 onuLogger.WithFields(log.Fields{
1278 "IntfId": o.PonPortID,
1279 "OnuId": o.ID,
1280 "SerialNumber": o.Sn(),
1281 }).Debug("shutting-down-onu")
1282 if err := o.HandleShutdownONU(); err != nil {
1283 return err
1284 }
1285 time.Sleep(timeout)
1286 onuLogger.WithFields(log.Fields{
1287 "IntfId": o.PonPortID,
1288 "OnuId": o.ID,
1289 "SerialNumber": o.Sn(),
1290 }).Debug("power-on-onu")
1291 if err := o.HandlePowerOnONU(); err != nil {
1292 return err
1293 }
1294 return nil
1295}
1296
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001297// BBR methods
1298
1299func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1300 omciMsg := openolt.OmciMsg{
1301 IntfId: intfId,
1302 OnuId: onuId,
1303 Pkt: pktBytes,
1304 }
1305
1306 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1307 log.WithFields(log.Fields{
1308 "IntfId": intfId,
1309 "OnuId": onuId,
1310 "SerialNumber": common.OnuSnToString(sn),
1311 "Pkt": omciMsg.Pkt,
1312 }).Fatalf("Failed to send MIB Reset")
1313 }
1314 log.WithFields(log.Fields{
1315 "IntfId": intfId,
1316 "OnuId": onuId,
1317 "SerialNumber": common.OnuSnToString(sn),
1318 "Pkt": omciMsg.Pkt,
1319 }).Tracef("Sent OMCI message %s", msgType)
1320}
1321
1322func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1323 var next uint16
1324 if len(highPriority) > 0 && highPriority[0] {
1325 next = onu.hpTid
1326 onu.hpTid += 1
1327 if onu.hpTid < 0x8000 {
1328 onu.hpTid = 0x8000
1329 }
1330 } else {
1331 next = onu.tid
1332 onu.tid += 1
1333 if onu.tid >= 0x8000 {
1334 onu.tid = 1
1335 }
1336 }
1337 return next
1338}
1339
1340// TODO move this method in responders/omcisim
1341func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1342 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1343 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1344}
1345
Matteo Scandolof9d43412021-01-12 11:11:34 -08001346// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1347func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1348
1349 // we need to encode the packet in HEX
1350 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1351 hex.Encode(pkt, msg.OmciInd.Pkt)
1352 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1353 if err != nil {
1354 log.WithFields(log.Fields{
1355 "IntfId": o.PonPortID,
1356 "SerialNumber": o.Sn(),
1357 "omciPacket": msg.OmciInd.Pkt,
1358 }).Error("BBR Cannot parse OMCI packet")
1359 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001360
1361 log.WithFields(log.Fields{
1362 "IntfId": msg.OmciInd.IntfId,
1363 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001364 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001365 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001366 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301367 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001368 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001369 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001370 log.WithFields(log.Fields{
1371 "IntfId": msg.OmciInd.IntfId,
1372 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001373 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001374 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001375 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001376 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001377 case omci.MibResetResponseType:
1378 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1379 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1380 case omci.MibUploadResponseType:
1381 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1382 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1383 case omci.MibUploadNextResponseType:
1384 o.seqNumber++
1385
1386 if o.seqNumber > 290 {
1387 // 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 -08001388 // 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 -08001389 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001390 onuLogger.WithFields(log.Fields{
1391 "OnuId": o.ID,
1392 "IntfId": o.PonPortID,
1393 "OnuSn": o.Sn(),
1394 }).Errorf("Error while transitioning ONU State %v", err)
1395 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001396 } else {
1397 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1398 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001399 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001400 }
1401}
1402
1403func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1404
1405 classifierProto := openolt.Classifier{
1406 EthType: uint32(layers.EthernetTypeEAPOL),
1407 OVid: 4091,
1408 }
1409
1410 actionProto := openolt.Action{}
1411
1412 downstreamFlow := openolt.Flow{
1413 AccessIntfId: int32(o.PonPortID),
1414 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001415 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001416 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001417 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001418 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001419 Classifier: &classifierProto,
1420 Action: &actionProto,
1421 Priority: int32(100),
1422 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001423 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1424 // AllocId and GemPorts need to be unique per PON
1425 // for now use the ONU-ID, will need to change once we support multiple UNIs
1426 AllocId: int32(o.ID),
1427 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001428 }
1429
1430 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1431 log.WithFields(log.Fields{
1432 "IntfId": o.PonPortID,
1433 "OnuId": o.ID,
1434 "FlowId": downstreamFlow.FlowId,
1435 "PortNo": downstreamFlow.PortNo,
1436 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001437 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001438 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001439 }
1440 log.WithFields(log.Fields{
1441 "IntfId": o.PonPortID,
1442 "OnuId": o.ID,
1443 "FlowId": downstreamFlow.FlowId,
1444 "PortNo": downstreamFlow.PortNo,
1445 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1446 }).Info("Sent EAPOL Flow")
1447}
1448
1449func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001450
1451 // BBR only works with a single service (ATT HSIA)
1452 hsia := o.Services[0].(*Service)
1453
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001454 classifierProto := openolt.Classifier{
1455 EthType: uint32(layers.EthernetTypeIPv4),
1456 SrcPort: uint32(68),
1457 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001458 OVid: uint32(hsia.CTag),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001459 }
1460
1461 actionProto := openolt.Action{}
1462
1463 downstreamFlow := openolt.Flow{
1464 AccessIntfId: int32(o.PonPortID),
1465 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001466 UniId: int32(0), // FIXME do not hardcode this
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001467 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001468 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001469 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001470 Classifier: &classifierProto,
1471 Action: &actionProto,
1472 Priority: int32(100),
1473 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001474 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1475 // AllocId and GemPorts need to be unique per PON
1476 // for now use the ONU-ID, will need to change once we support multiple UNIs
1477 AllocId: int32(o.ID),
1478 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001479 }
1480
1481 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1482 log.WithFields(log.Fields{
1483 "IntfId": o.PonPortID,
1484 "OnuId": o.ID,
1485 "FlowId": downstreamFlow.FlowId,
1486 "PortNo": downstreamFlow.PortNo,
1487 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001488 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001489 }).Fatalf("Failed to send DHCP Flow")
1490 }
1491 log.WithFields(log.Fields{
1492 "IntfId": o.PonPortID,
1493 "OnuId": o.ID,
1494 "FlowId": downstreamFlow.FlowId,
1495 "PortNo": downstreamFlow.PortNo,
1496 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1497 }).Info("Sent DHCP Flow")
1498}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301499
1500// DeleteFlow method search and delete flowKey from the onu flows slice
1501func (onu *Onu) DeleteFlow(key FlowKey) {
1502 for pos, flowKey := range onu.Flows {
1503 if flowKey == key {
1504 // delete the flowKey by shifting all flowKeys by one
1505 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1506 t := make([]FlowKey, len(onu.Flows))
1507 copy(t, onu.Flows)
1508 onu.Flows = t
1509 break
1510 }
1511 }
1512}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301513
1514func (onu *Onu) ReDiscoverOnu() {
1515 // Wait for few seconds to be sure of the cleanup
1516 time.Sleep(5 * time.Second)
1517
1518 onuLogger.WithFields(log.Fields{
1519 "IntfId": onu.PonPortID,
1520 "OnuId": onu.ID,
1521 "OnuSn": onu.Sn(),
1522 }).Debug("Send ONU Re-Discovery")
1523
1524 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001525 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301526 log.WithFields(log.Fields{
1527 "IntfId": onu.PonPortID,
1528 "OnuSn": onu.Sn(),
1529 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001530 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301531 }
1532
Matteo Scandolocedde462021-03-09 17:37:16 -08001533 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301534 log.WithFields(log.Fields{
1535 "IntfId": onu.PonPortID,
1536 "OnuSn": onu.Sn(),
1537 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001538 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301539 }
1540}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001541
1542func (onu *Onu) addGemPortToService(gemport uint32, ethType uint32, oVlan uint32, iVlan uint32) {
1543 for _, s := range onu.Services {
1544 if service, ok := s.(*Service); ok {
1545 // EAPOL is a strange case, as packets are untagged
1546 // but we assume we will have a single service requiring EAPOL
1547 if ethType == uint32(layers.EthernetTypeEAPOL) && service.NeedsEapol {
1548 service.GemPort = gemport
1549 }
1550
1551 // For DHCP services we single tag the outgoing packets,
1552 // thus the flow only contains the CTag and we can use that to match the service
1553 if ethType == uint32(layers.EthernetTypeIPv4) && service.NeedsDhcp && service.CTag == int(oVlan) {
1554 service.GemPort = gemport
1555 }
1556
1557 // for dataplane services match both C and S tags
1558 if service.CTag == int(iVlan) && service.STag == int(oVlan) {
1559 service.GemPort = gemport
1560 }
1561 }
1562 }
1563}
1564
1565func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
1566 for _, s := range onu.Services {
1567 service := s.(*Service)
1568 if service.HwAddress.String() == macAddress.String() {
1569 return service, nil
1570 }
1571 }
1572 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1573}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301574
1575func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1576 switch alarmType {
1577 case "ONU_ALARM_LOS":
1578 msg := bbsim.Message{
1579 Type: bbsim.UniStatusAlarm,
1580 Data: bbsim.UniStatusAlarmMessage{
1581 OnuSN: o.SerialNumber,
1582 OnuID: o.ID,
1583 EntityID: 257,
1584 RaiseOMCIAlarm: raiseOMCIAlarm,
1585 },
1586 }
1587 o.Channel <- msg
1588 }
1589
1590}
1591
1592func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1593 o.onuAlarmsInfoLock.Lock()
1594 defer o.onuAlarmsInfoLock.Unlock()
1595 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1596 if alarmInfo.SequenceNo == 255 {
1597 alarmInfo.SequenceNo = 1
1598 } else {
1599 alarmInfo.SequenceNo++
1600 }
1601 o.onuAlarmsInfo[key] = alarmInfo
1602 return alarmInfo.SequenceNo
1603 } else {
1604 // This is the first time alarm notification message is being sent
1605 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1606 SequenceNo: 1,
1607 }
1608 return 1
1609 }
1610}