blob: 0f04039d917c37bbc3b3d90bb34b954dd9dda28b [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"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000023 "sync"
24
Matteo Scandolof9d43412021-01-12 11:11:34 -080025 pb "github.com/opencord/bbsim/api/bbsim"
26 "github.com/opencord/bbsim/internal/bbsim/alarmsim"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000027
28 "net"
29 "strconv"
30 "time"
Himani Chawla13b1ee02021-03-15 01:43:53 +053031
Matteo Scandolo4a036262020-08-17 15:56:13 -070032 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
33 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
34 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080035 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
36 me "github.com/opencord/omci-lib-go/generated"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010037
Matteo Scandolo3bc73742019-08-20 14:04:04 -070038 "github.com/google/gopacket/layers"
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070039 "github.com/jpillora/backoff"
Matteo Scandolo4747d292019-08-05 11:50:18 -070040 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070041 "github.com/opencord/bbsim/internal/common"
42 omcilib "github.com/opencord/bbsim/internal/common/omci"
Matteo Scandolof9d43412021-01-12 11:11:34 -080043 "github.com/opencord/omci-lib-go"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070044 "github.com/opencord/voltha-protos/v4/go/openolt"
45 "github.com/opencord/voltha-protos/v4/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070046 log "github.com/sirupsen/logrus"
47)
48
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070049var onuLogger = log.WithFields(log.Fields{
50 "module": "ONU",
51})
52
Matteo Scandolocedde462021-03-09 17:37:16 -080053const (
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000054 maxOmciMsgCounter = 10
55)
56
57const (
Matteo Scandolocedde462021-03-09 17:37:16 -080058 // ONU transitions
59 OnuTxInitialize = "initialize"
60 OnuTxDiscover = "discover"
61 OnuTxEnable = "enable"
62 OnuTxDisable = "disable"
63 OnuTxPonDisable = "pon_disable"
64 OnuTxStartImageDownload = "start_image_download"
65 OnuTxProgressImageDownload = "progress_image_download"
66 OnuTxCompleteImageDownload = "complete_image_download"
67 OnuTxFailImageDownload = "fail_image_download"
68 OnuTxActivateImage = "activate_image"
69 OnuTxCommitImage = "commit_image"
70
71 // ONU States
72 OnuStateCreated = "created"
73 OnuStateInitialized = "initialized"
74 OnuStateDiscovered = "discovered"
75 OnuStateEnabled = "enabled"
76 OnuStateDisabled = "disabled"
77 OnuStatePonDisabled = "pon_disabled"
78 OnuStateImageDownloadStarted = "image_download_started"
79 OnuStateImageDownloadInProgress = "image_download_in_progress"
80 OnuStateImageDownloadComplete = "image_download_completed"
81 OnuStateImageDownloadError = "image_download_error"
82 OnuStateImageActivated = "software_image_activated"
83 OnuStateImageCommitted = "software_image_committed"
84
85 // BBR ONU States and Transitions
86 BbrOnuTxSendEapolFlow = "send_eapol_flow"
87 BbrOnuStateEapolFlowSent = "eapol_flow_sent"
88 BbrOnuTxSendDhcpFlow = "send_dhcp_flow"
89 BbrOnuStateDhcpFlowSent = "dhcp_flow_sent"
90)
91
Pragya Arya8bdb4532020-03-02 17:08:09 +053092type FlowKey struct {
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070093 ID uint64
Pragya Arya8bdb4532020-03-02 17:08:09 +053094 Direction string
95}
96
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070097type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -080098 ID uint32
99 PonPortID uint32
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700100 PonPort *PonPort
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800101 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +0530102 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
103 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandolo4a036262020-08-17 15:56:13 -0700104
105 Services []ServiceIf
106
107 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800108 // ONU State
Matteo Scandolo27428702019-10-11 16:21:16 -0700109 // PortNo comes with flows and it's used when sending packetIndications,
110 // There is one PortNo per UNI Port, for now we're only storing the first one
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700111 // FIXME add support for multiple UNIs (each UNI has a different PortNo)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800112 PortNo uint32
113 Flows []FlowKey
114 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700115
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700116 OperState *fsm.FSM
117 SerialNumber *openolt.SerialNumber
118
Matteo Scandolof9d43412021-01-12 11:11:34 -0800119 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700120
121 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800122 MibDataSync uint8
123 ImageSoftwareExpectedSections int
124 ImageSoftwareReceivedSections int
125 ActiveImageEntityId uint16
126 CommittedImageEntityId uint16
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000127 OmciResponseRate uint8
128 OmciMsgCounter uint8
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800129
130 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700131 tid uint16
132 hpTid uint16
133 seqNumber uint16
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700134
Anand S Katti09541352020-01-29 15:54:01 +0530135 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
136 TrafficSchedulers *tech_profile.TrafficSchedulers
Himani Chawla13b1ee02021-03-15 01:43:53 +0530137 onuAlarmsInfoLock sync.RWMutex
138 onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700139}
140
Matteo Scandolo99f18462019-10-28 14:14:28 -0700141func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700142 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700143}
144
Matteo Scandolo4a036262020-08-17 15:56:13 -0700145func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, isMock bool) *Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700146
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700147 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800148 ID: id,
149 PonPortID: pon.ID,
150 PonPort: pon,
151 PortNo: 0,
152 tid: 0x1,
153 hpTid: 0x8000,
154 seqNumber: 0,
155 DoneChannel: make(chan bool, 1),
156 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
157 Flows: []FlowKey{},
158 DiscoveryDelay: delay,
159 MibDataSync: 0,
160 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
161 ImageSoftwareReceivedSections: 0,
162 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
163 CommittedImageEntityId: 0,
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000164 OmciResponseRate: olt.OmciResponseRate,
165 OmciMsgCounter: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700166 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800167 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700168 // NOTE this state machine is used to track the operational
169 // state as requested by VOLTHA
170 o.OperState = getOperStateFSM(func(e *fsm.Event) {
171 onuLogger.WithFields(log.Fields{
172 "ID": o.ID,
173 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
174 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530175 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700176 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
177 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800178 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700179 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700180 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800181 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
182 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
183 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100184 // 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 -0800185 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530186 // 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 -0800187 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStatePonDisabled},
188 // Software Image Download related states
189 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError}, Dst: OnuStateImageDownloadStarted},
190 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
191 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
192 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
193 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
194 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700195 // BBR States
196 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800197 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
198 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700199 },
200 fsm.Callbacks{
201 "enter_state": func(e *fsm.Event) {
202 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700203 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700204 fmt.Sprintf("enter_%s", OnuStateInitialized): func(e *fsm.Event) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100205 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800206 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800207
Matteo Scandolocedde462021-03-09 17:37:16 -0800208 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800209 onuLogger.WithFields(log.Fields{
210 "OnuId": o.ID,
211 "IntfId": o.PonPortID,
212 "OnuSn": o.Sn(),
213 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
214 }
215
Pragya Arya1cbefa42020-01-13 12:15:29 +0530216 if !isMock {
217 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700218 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530219 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100220 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700221 fmt.Sprintf("enter_%s", OnuStateDiscovered): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800222 msg := bbsim.Message{
223 Type: bbsim.OnuDiscIndication,
224 Data: bbsim.OnuDiscIndicationMessage{
225 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100226 },
227 }
228 o.Channel <- msg
229 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700230 fmt.Sprintf("enter_%s", OnuStateEnabled): func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800231
232 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
233 onuLogger.WithFields(log.Fields{
234 "IntfId": o.PonPortID,
235 "OnuId": o.ID,
236 "SerialNumber": o.Sn(),
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700237 }).Errorf("onu-id-duplicated-with-%s", common.OnuSnToString(sn))
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800238 return
239 } else {
240 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
241 }
242
Matteo Scandolof9d43412021-01-12 11:11:34 -0800243 msg := bbsim.Message{
244 Type: bbsim.OnuIndication,
245 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700246 OnuSN: o.SerialNumber,
247 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800248 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700249 },
250 }
251 o.Channel <- msg
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700252
253 // Once the ONU is enabled start listening for packets
254 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700255 s.Initialize(o.PonPort.Olt.OpenoltStream)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700256 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700257 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700258 fmt.Sprintf("enter_%s", OnuStateDisabled): func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700259
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700260 o.cleanupOnuState()
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700261
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700262 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800263 if err := o.OperState.Event("disable"); err != nil {
264 onuLogger.WithFields(log.Fields{
265 "OnuId": o.ID,
266 "IntfId": o.PonPortID,
267 "OnuSn": o.Sn(),
268 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
269 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700270 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800271 msg := bbsim.Message{
272 Type: bbsim.OnuIndication,
273 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700274 OnuSN: o.SerialNumber,
275 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800276 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700277 },
278 }
279 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530280
281 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100282 // terminate the ONU's ProcessOnuMessages Go routine
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530283 if len(o.FlowIds) == 0 {
284 close(o.Channel)
285 }
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700286
287 for _, s := range o.Services {
288 s.Disable()
289 }
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700290
291 },
292 fmt.Sprintf("enter_%s", OnuStatePonDisabled): func(event *fsm.Event) {
293 o.cleanupOnuState()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700294 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700295 // BBR states
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700296 fmt.Sprintf("enter_%s", BbrOnuStateEapolFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800297 msg := bbsim.Message{
298 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700299 }
300 o.Channel <- msg
301 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700302 fmt.Sprintf("enter_%s", BbrOnuStateDhcpFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800303 msg := bbsim.Message{
304 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700305 }
306 o.Channel <- msg
307 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700308 },
309 )
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100310
Matteo Scandolo27428702019-10-11 16:21:16 -0700311 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700312}
313
William Kurkian0418bc82019-11-06 12:16:24 -0500314func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700315 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700316 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700317 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700318 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700319 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
320}
321
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700322// cleanupOnuState this method is to clean the local state when the ONU is disabled
323func (o *Onu) cleanupOnuState() {
324 // clean the ONU state
325 o.PortNo = 0
326 o.Flows = []FlowKey{}
327 o.PonPort.removeOnuId(o.ID)
328 o.PonPort.removeAllocId(o.SerialNumber)
329 o.PonPort.removeGemPortBySn(o.SerialNumber)
330
331 o.onuAlarmsInfoLock.Lock()
332 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
333 o.onuAlarmsInfoLock.Unlock()
334}
335
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100336// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000337func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700338 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100339 "onuID": o.ID,
340 "onuSN": o.Sn(),
341 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700342 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100343 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700344
David Bainbridge103cf022019-12-16 20:11:35 +0000345loop:
346 for {
347 select {
348 case <-ctx.Done():
349 onuLogger.WithFields(log.Fields{
350 "onuID": o.ID,
351 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700352 }).Debug("ONU message handling canceled via context")
353 break loop
354 case <-stream.Context().Done():
355 onuLogger.WithFields(log.Fields{
356 "onuID": o.ID,
357 "onuSN": o.Sn(),
358 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000359 break loop
360 case message, ok := <-o.Channel:
361 if !ok || ctx.Err() != nil {
362 onuLogger.WithFields(log.Fields{
363 "onuID": o.ID,
364 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700365 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000366 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700367 }
David Bainbridge103cf022019-12-16 20:11:35 +0000368 onuLogger.WithFields(log.Fields{
369 "onuID": o.ID,
370 "onuSN": o.Sn(),
371 "messageType": message.Type,
372 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700373
David Bainbridge103cf022019-12-16 20:11:35 +0000374 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800375 case bbsim.OnuDiscIndication:
376 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000377 // 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 +0530378 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000379 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800380 case bbsim.OnuIndication:
381 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000382 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800383 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800384 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800385 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200386 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800387 case bbsim.UniStatusAlarm:
388 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530389 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
390 MeInstance: msg.EntityID,
391 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
392 }
393 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
394 o.onuAlarmsInfoLock.Lock()
395 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
396 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
397 if pkt != nil { //pkt will be nil if we are unable to create the alarm
398 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
399 onuLogger.WithFields(log.Fields{
400 "IntfId": o.PonPortID,
401 "SerialNumber": o.Sn(),
402 "omciPacket": pkt,
403 "adminState": msg.AdminState,
404 "entityID": msg.EntityID,
405 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
406 alarmInfo.SequenceNo--
407 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800408 onuLogger.WithFields(log.Fields{
409 "IntfId": o.PonPortID,
410 "SerialNumber": o.Sn(),
411 "omciPacket": pkt,
412 "adminState": msg.AdminState,
413 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530414 }).Trace("UNI-Link-alarm-sent")
415 if alarmBitMap == [28]byte{0} {
416 delete(o.onuAlarmsInfo, onuAlarmMapKey)
417 } else {
418 alarmInfo.AlarmBitMap = alarmBitMap
419 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
420 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800421 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530422 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800423 case bbsim.FlowAdd:
424 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700425 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800426 case bbsim.FlowRemoved:
427 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700428 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800429 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700430
Matteo Scandolof9d43412021-01-12 11:11:34 -0800431 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000432
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700433 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000434 "IntfId": msg.IntfId,
435 "OnuId": msg.OnuId,
436 "pktType": msg.Type,
437 }).Trace("Received OnuPacketOut Message")
438
Matteo Scandolo618a6582020-09-09 12:21:29 -0700439 if msg.Type == packetHandlers.EAPOL || msg.Type == packetHandlers.DHCP {
440
441 service, err := o.findServiceByMacAddress(msg.MacAddress)
442 if err != nil {
443 onuLogger.WithFields(log.Fields{
444 "IntfId": msg.IntfId,
445 "OnuId": msg.OnuId,
446 "pktType": msg.Type,
447 "MacAddress": msg.MacAddress,
448 "Pkt": hex.EncodeToString(msg.Packet.Data()),
449 "OnuSn": o.Sn(),
450 }).Error("Cannot find Service associated with packet")
451 return
452 }
453 service.PacketCh <- msg
454 } else if msg.Type == packetHandlers.IGMP {
455 // if it's an IGMP packet we assume we have a single IGMP service
456 for _, s := range o.Services {
457 service := s.(*Service)
458
459 if service.NeedsIgmp {
460 service.PacketCh <- msg
461 }
462 }
David Bainbridge103cf022019-12-16 20:11:35 +0000463 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700464
Matteo Scandolof9d43412021-01-12 11:11:34 -0800465 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000466 // NOTE we only receive BBR packets here.
467 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
468 // 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 -0800469 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000470
471 log.WithFields(log.Fields{
472 "IntfId": msg.IntfId,
473 "OnuId": msg.OnuId,
474 "pktType": msg.Type,
475 }).Trace("Received OnuPacketIn Message")
476
477 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700478 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 +0000479 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700480 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000481 }
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700482 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800483 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800484 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800485 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
486 o.handleOmciResponse(msg, client)
487 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000488 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800489 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000490 o.sendDhcpFlow(client)
491 default:
492 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700493 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700494 }
495 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100496 onuLogger.WithFields(log.Fields{
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700497 "onuID": o.ID,
498 "onuSN": o.Sn(),
499 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100500 }).Debug("Stopped handling ONU Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700501}
502
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800503func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700504 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700505 sn.VendorId = []byte("BBSM")
506 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700507 return sn
508}
509
Matteo Scandolof9d43412021-01-12 11:11:34 -0800510func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700511 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800512 IntfId: o.PonPortID,
513 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700514 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700515
Matteo Scandolo4747d292019-08-05 11:50:18 -0700516 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700517 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700518 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700519 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700520
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700521 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800522 "IntfId": o.PonPortID,
523 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700524 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700525 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800526 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800527
528 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
529 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800530 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800531 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800532 o.sendOnuDiscIndication(msg, stream)
533 }
534 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700535}
536
Matteo Scandolof9d43412021-01-12 11:11:34 -0800537func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800538 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
539 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700540
541 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700542 IntfId: o.PonPortID,
543 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700544 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700545 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700546 SerialNumber: o.SerialNumber,
547 }}
548 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800549 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700550 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700551 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700552 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700553 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800554 "IntfId": o.PonPortID,
555 "OnuId": o.ID,
556 "VolthaOnuId": msg.OnuID,
557 "OperState": msg.OperState.String(),
558 "AdminState": msg.OperState.String(),
559 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700560 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700561
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700562}
563
Matteo Scandolof9d43412021-01-12 11:11:34 -0800564func (o *Onu) HandleShutdownONU() error {
565
566 dyingGasp := pb.ONUAlarmRequest{
567 AlarmType: "DYING_GASP",
568 SerialNumber: o.Sn(),
569 Status: "on",
570 }
571
572 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
573 onuLogger.WithFields(log.Fields{
574 "OnuId": o.ID,
575 "IntfId": o.PonPortID,
576 "OnuSn": o.Sn(),
577 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
578 return err
579 }
580
581 losReq := pb.ONUAlarmRequest{
582 AlarmType: "ONU_ALARM_LOS",
583 SerialNumber: o.Sn(),
584 Status: "on",
585 }
586
587 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
588 onuLogger.WithFields(log.Fields{
589 "OnuId": o.ID,
590 "IntfId": o.PonPortID,
591 "OnuSn": o.Sn(),
592 }).Errorf("Cannot send LOS: %s", err.Error())
593
594 return err
595 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530596 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800597 // TODO if it's the last ONU on the PON, then send a PON LOS
598
Matteo Scandolocedde462021-03-09 17:37:16 -0800599 if err := o.InternalState.Event(OnuTxDisable); 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 shutdown ONU: %s", err.Error())
605 return err
606 }
607
608 return nil
609}
610
611func (o *Onu) HandlePowerOnONU() error {
612 intitalState := o.InternalState.Current()
613
614 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800615 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
616 if err := o.InternalState.Event(OnuTxInitialize); 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
626 // turn off the LOS Alarm
627 losReq := pb.ONUAlarmRequest{
628 AlarmType: "ONU_ALARM_LOS",
629 SerialNumber: o.Sn(),
630 Status: "off",
631 }
632
633 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
634 onuLogger.WithFields(log.Fields{
635 "OnuId": o.ID,
636 "IntfId": o.PonPortID,
637 "OnuSn": o.Sn(),
638 }).Errorf("Cannot send LOS: %s", err.Error())
639 return err
640 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530641 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800642
643 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800644 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800645 onuLogger.WithFields(log.Fields{
646 "OnuId": o.ID,
647 "IntfId": o.PonPortID,
648 "OnuSn": o.Sn(),
649 }).Errorf("Cannot poweron ONU: %s", err.Error())
650 return err
651 }
652
653 // move o directly to enable state only when its a powercycle case
654 // in case of first time o poweron o will be moved to enable on
655 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800656 if intitalState == OnuStateDisabled {
657 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800658 onuLogger.WithFields(log.Fields{
659 "OnuId": o.ID,
660 "IntfId": o.PonPortID,
661 "OnuSn": o.Sn(),
662 }).Errorf("Cannot enable ONU: %s", err.Error())
663 return err
664 }
665 }
666
667 return nil
668}
669
670func (o *Onu) SetAlarm(alarmType string, status string) error {
671 alarmReq := pb.ONUAlarmRequest{
672 AlarmType: alarmType,
673 SerialNumber: o.Sn(),
674 Status: status,
675 }
676
677 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
678 if err != nil {
679 return err
680 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530681 raiseAlarm := false
682 if alarmReq.Status == "on" {
683 raiseAlarm = true
684 }
685 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800686 return nil
687}
688
689func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530690 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700691 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530692 if err != nil {
693 log.Errorf("error in getting msgType %v", err)
694 return
695 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800696 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530697 o.seqNumber = 0
698 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800699 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530700 o.seqNumber++
701 if o.seqNumber > 290 {
702 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
703 }
704 }
705 }
706}
707
Scott Bakerb90c4312020-03-12 21:33:25 -0700708// Create a TestResponse packet and send it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800709func (o *Onu) sendTestResult(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolob5913142021-03-19 16:10:18 -0700710 resp, err := omcilib.BuildTestResult(msg.OmciPkt.Data())
Scott Bakerb90c4312020-03-12 21:33:25 -0700711 if err != nil {
712 return err
713 }
714
715 var omciInd openolt.OmciIndication
716 omciInd.IntfId = o.PonPortID
717 omciInd.OnuId = o.ID
718 omciInd.Pkt = resp
719
720 omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
721 if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
Scott Bakerb90c4312020-03-12 21:33:25 -0700722 return err
723 }
724 onuLogger.WithFields(log.Fields{
725 "IntfId": o.PonPortID,
726 "SerialNumber": o.Sn(),
727 "omciPacket": omciInd.Pkt,
728 }).Tracef("Sent TestResult OMCI message")
729
730 return nil
731}
732
Matteo Scandolof9d43412021-01-12 11:11:34 -0800733// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
734// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200735func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800736
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700737 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700738 "omciMsgType": msg.OmciMsg.MessageType,
739 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
740 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700741 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700742 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800743 }).Trace("omci-message-decoded")
744
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000745 if o.OmciMsgCounter < maxOmciMsgCounter {
746 o.OmciMsgCounter++
747 } else {
748 o.OmciMsgCounter = 1
749 }
750 if o.OmciMsgCounter > o.OmciResponseRate {
751 onuLogger.WithFields(log.Fields{
752 "OmciMsgCounter": o.OmciMsgCounter,
753 "OmciResponseRate": o.OmciResponseRate,
754 "omciMsgType": msg.OmciMsg.MessageType,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200755 }).Debug("skipping-omci-msg-response")
756 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000757 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800758 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800759 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700760 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800761 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800762 onuLogger.WithFields(log.Fields{
763 "IntfId": o.PonPortID,
764 "OnuId": o.ID,
765 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700766 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700767 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800768 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700769
770 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
771 o.PonPort.removeAllocId(o.SerialNumber)
772 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800773 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800774 case omci.MibUploadRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700775 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800776 case omci.MibUploadNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700777 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800778 case omci.GetRequestType:
Girish Gowdra996d81e2021-04-21 16:16:27 -0700779 onuDown := o.OperState.Current() == "down"
780 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId, o.CommittedImageEntityId, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800781 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800782 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700783 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800784 switch msgObj.EntityClass {
785 case me.PhysicalPathTerminationPointEthernetUniClassID:
786 // if we're Setting a PPTP state
787 // we need to send the appropriate alarm
788
789 if msgObj.EntityInstance == 257 {
790 // for now we're only caring about the first UNI
791 // NOTE that the EntityID for the UNI port is for now hardcoded in
792 // omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
793 // are reported during the MIB Upload sequence
794 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530795 raiseOMCIAlarm := false
796 if adminState == 1 {
797 raiseOMCIAlarm = true
Girish Gowdra996d81e2021-04-21 16:16:27 -0700798 // set the OperState to disabled
799 if err := o.OperState.Event(OnuTxDisable); err != nil {
800 onuLogger.WithFields(log.Fields{
801 "OnuId": o.ID,
802 "IntfId": o.PonPortID,
803 "OnuSn": o.Sn(),
804 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
805 }
806 } else {
807 // set the OperState to enabled
808 if err := o.OperState.Event(OnuTxEnable); err != nil {
809 onuLogger.WithFields(log.Fields{
810 "OnuId": o.ID,
811 "IntfId": o.PonPortID,
812 "OnuSn": o.Sn(),
813 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
814 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530815 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800816 msg := bbsim.Message{
817 Type: bbsim.UniStatusAlarm,
818 Data: bbsim.UniStatusAlarmMessage{
Himani Chawla13b1ee02021-03-15 01:43:53 +0530819 OnuSN: o.SerialNumber,
820 OnuID: o.ID,
821 AdminState: adminState,
822 EntityID: msgObj.EntityInstance,
823 RaiseOMCIAlarm: raiseOMCIAlarm,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800824 },
825 }
826 o.Channel <- msg
827 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800828 case me.TContClassID:
829 allocId := msgObj.Attributes["AllocId"].(uint16)
830
831 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
832 // otherwise we are adding it
833 if allocId == 255 || allocId == 65535 {
834 onuLogger.WithFields(log.Fields{
835 "IntfId": o.PonPortID,
836 "OnuId": o.ID,
837 "TContId": msgObj.EntityInstance,
838 "AllocId": allocId,
839 "SerialNumber": o.Sn(),
840 }).Trace("freeing-alloc-id-via-omci")
841 o.PonPort.removeAllocId(o.SerialNumber)
842 } else {
843 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
844 onuLogger.WithFields(log.Fields{
845 "IntfId": o.PonPortID,
846 "OnuId": o.ID,
847 "AllocId": allocId,
848 "SerialNumber": o.Sn(),
849 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
850 success = false
851 } else {
852 onuLogger.WithFields(log.Fields{
853 "IntfId": o.PonPortID,
854 "OnuId": o.ID,
855 "TContId": msgObj.EntityInstance,
856 "AllocId": allocId,
857 "SerialNumber": o.Sn(),
858 }).Trace("storing-alloc-id-via-omci")
859 o.PonPort.storeAllocId(allocId, o.SerialNumber)
860 }
861 }
862
863 }
864
865 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700866 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800867 o.MibDataSync++
868 }
869 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700870 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800871 }
872 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800873 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
874 var used bool
875 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700876 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800877 if err == nil {
878 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700879 // GemPort 4069 is reserved for multicast and shared across ONUs
880 if msgObj.EntityInstance != 4069 {
881 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
882 onuLogger.WithFields(log.Fields{
883 "IntfId": o.PonPortID,
884 "OnuId": o.ID,
885 "GemPortId": msgObj.EntityInstance,
886 "SerialNumber": o.Sn(),
887 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
888 } else {
889 onuLogger.WithFields(log.Fields{
890 "IntfId": o.PonPortID,
891 "OnuId": o.ID,
892 "GemPortId": msgObj.EntityInstance,
893 "SerialNumber": o.Sn(),
894 }).Trace("storing-gem-port-id-via-omci")
895 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
896 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800897 }
898 }
899 }
900
901 // if the gemPort is valid then increment the MDS and return a successful response
902 // otherwise fail the request
903 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
904 // validation this check will need to be rewritten
905 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700906 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800907 o.MibDataSync++
908 }
909 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700910 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800911 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800912 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700913 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800914 if err == nil {
915 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
916 onuLogger.WithFields(log.Fields{
917 "IntfId": o.PonPortID,
918 "OnuId": o.ID,
919 "GemPortId": msgObj.EntityInstance,
920 "SerialNumber": o.Sn(),
921 }).Trace("freeing-gem-port-id-via-omci")
922 o.PonPort.removeGemPort(msgObj.EntityInstance)
923 }
924 }
925
Matteo Scandolob5913142021-03-19 16:10:18 -0700926 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800927 o.MibDataSync++
928 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800929 case omci.RebootRequestType:
930
Matteo Scandolob5913142021-03-19 16:10:18 -0700931 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800932
933 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800934 // we run this in a separate goroutine so that
935 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800936 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800937 if err := o.Reboot(10 * time.Second); err != nil {
938 log.WithFields(log.Fields{
939 "IntfId": o.PonPortID,
940 "OnuId": o.ID,
941 "SerialNumber": o.Sn(),
942 "err": err,
943 }).Error("cannot-reboot-onu-after-omci-reboot-request")
944 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800945 }()
946 case omci.TestRequestType:
947
948 // Test message is special, it requires sending two packets:
949 // first packet: TestResponse, says whether test was started successully, handled by omci-sim
950 // second packet, TestResult, reports the result of running the self-test
951 // TestResult can come some time after a TestResponse
952 // TODO: Implement some delay between the TestResponse and the TestResult
Matteo Scandolob5913142021-03-19 16:10:18 -0700953 isTest, err := omcilib.IsTestRequest(msg.OmciPkt.Data())
Matteo Scandolof9d43412021-01-12 11:11:34 -0800954 if (err == nil) && (isTest) {
955 if sendErr := o.sendTestResult(msg, stream); sendErr != nil {
956 onuLogger.WithFields(log.Fields{
957 "IntfId": o.PonPortID,
Matteo Scandolocedde462021-03-09 17:37:16 -0800958 "OnuId": o.ID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800959 "SerialNumber": o.Sn(),
Matteo Scandolob5913142021-03-19 16:10:18 -0700960 "omciPacket": msg.OmciPkt.Data(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800961 "msg": msg,
962 "err": sendErr,
963 }).Error("send-TestResult-indication-failed")
964 }
965 }
Girish Gowdraa539f522021-02-15 23:00:45 -0800966 case omci.SynchronizeTimeRequestType:
967 // MDS counter increment is not required for this message type
Matteo Scandolob5913142021-03-19 16:10:18 -0700968 responsePkt, _ = omcilib.CreateSyncTimeResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -0800969 case omci.StartSoftwareDownloadRequestType:
970
971 o.ImageSoftwareReceivedSections = 0
972
Matteo Scandolob5913142021-03-19 16:10:18 -0700973 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
Matteo Scandolocedde462021-03-09 17:37:16 -0800974
Matteo Scandolob5913142021-03-19 16:10:18 -0700975 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -0800976 o.MibDataSync++
977 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
978 onuLogger.WithFields(log.Fields{
979 "OnuId": o.ID,
980 "IntfId": o.PonPortID,
981 "OnuSn": o.Sn(),
982 "Err": err.Error(),
983 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
984 }
985 } else {
986 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700987 "OmciMsgType": msg.OmciMsg.MessageType,
988 "TransCorrId": msg.OmciMsg.TransactionID,
989 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -0800990 "IntfId": o.PonPortID,
991 "SerialNumber": o.Sn(),
992 }).Error("error-while-processing-start-software-download-request")
993 }
994 case omci.DownloadSectionRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700995 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -0800996 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700997 "OmciMsgType": msg.OmciMsg.MessageType,
998 "TransCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolocedde462021-03-09 17:37:16 -0800999 "EntityInstance": msgObj.EntityInstance,
1000 "SectionNumber": msgObj.SectionNumber,
1001 "SectionData": msgObj.SectionData,
1002 }).Trace("received-download-section-request")
1003 o.ImageSoftwareReceivedSections++
1004 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1005 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1006 onuLogger.WithFields(log.Fields{
1007 "OnuId": o.ID,
1008 "IntfId": o.PonPortID,
1009 "OnuSn": o.Sn(),
1010 "Err": err.Error(),
1011 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1012 }
1013 }
1014 }
1015 case omci.DownloadSectionRequestWithResponseType:
1016 // NOTE we only need to respond if an ACK is requested
Matteo Scandolob5913142021-03-19 16:10:18 -07001017 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1018 if errResp != nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001019 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001020 "OmciMsgType": msg.OmciMsg.MessageType,
1021 "TransCorrId": msg.OmciMsg.TransactionID,
1022 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001023 "IntfId": o.PonPortID,
1024 "SerialNumber": o.Sn(),
1025 }).Error("error-while-processing-create-download-section-response")
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001026 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
Matteo Scandolocedde462021-03-09 17:37:16 -08001027 }
1028 o.ImageSoftwareReceivedSections++
1029
1030 case omci.EndSoftwareDownloadRequestType:
1031
1032 // In the startSoftwareDownload we get the image size and the window size.
1033 // We calculate how many DownloadSection we should receive and validate
1034 // that we got the correct amount when we receive this message
1035 success := true
1036 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1037 onuLogger.WithFields(log.Fields{
1038 "OnuId": o.ID,
1039 "IntfId": o.PonPortID,
1040 "OnuSn": o.Sn(),
1041 "ExpectedSections": o.ImageSoftwareExpectedSections,
1042 "ReceivedSections": o.ImageSoftwareReceivedSections,
1043 }).Errorf("onu-did-not-receive-all-image-sections")
1044 success = false
1045 }
1046
1047 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001048 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001049 o.MibDataSync++
1050 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1051 onuLogger.WithFields(log.Fields{
1052 "OnuId": o.ID,
1053 "IntfId": o.PonPortID,
1054 "OnuSn": o.Sn(),
1055 "Err": err.Error(),
1056 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1057 }
1058 } else {
1059 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001060 "OmciMsgType": msg.OmciMsg.MessageType,
1061 "TransCorrId": msg.OmciMsg.TransactionID,
1062 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001063 "IntfId": o.PonPortID,
1064 "SerialNumber": o.Sn(),
1065 }).Error("error-while-processing-end-software-download-request")
1066 }
1067 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001068 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001069 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1070 onuLogger.WithFields(log.Fields{
1071 "OnuId": o.ID,
1072 "IntfId": o.PonPortID,
1073 "OnuSn": o.Sn(),
1074 "Err": err.Error(),
1075 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1076 }
1077 }
1078 }
1079
1080 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001081 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001082 o.MibDataSync++
1083 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1084 onuLogger.WithFields(log.Fields{
1085 "OnuId": o.ID,
1086 "IntfId": o.PonPortID,
1087 "OnuSn": o.Sn(),
1088 "Err": err.Error(),
1089 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1090 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001091 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001092 o.ActiveImageEntityId = msgObj.EntityInstance
1093 } else {
1094 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1095 }
1096 onuLogger.WithFields(log.Fields{
1097 "OnuId": o.ID,
1098 "IntfId": o.PonPortID,
1099 "OnuSn": o.Sn(),
1100 "ActiveImageEntityId": o.ActiveImageEntityId,
1101 "CommittedImageEntityId": o.CommittedImageEntityId,
1102 }).Info("onu-software-image-activated")
1103
1104 // powercycle the ONU
1105 // we run this in a separate goroutine so that
1106 // the ActivateSoftwareResponse is sent to VOLTHA
1107 // NOTE do we need to wait before rebooting?
1108 go func() {
1109 if err := o.Reboot(10 * time.Second); err != nil {
1110 log.WithFields(log.Fields{
1111 "IntfId": o.PonPortID,
1112 "OnuId": o.ID,
1113 "SerialNumber": o.Sn(),
1114 "err": err,
1115 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1116 }
1117 }()
1118 }
1119 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001120 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001121 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001122 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001123 // TODO validate that the image to commit is:
1124 // - active
1125 // - not already committed
1126 o.CommittedImageEntityId = msgObj.EntityInstance
1127 } else {
1128 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1129 }
1130 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1131 onuLogger.WithFields(log.Fields{
1132 "OnuId": o.ID,
1133 "IntfId": o.PonPortID,
1134 "OnuSn": o.Sn(),
1135 "Err": err.Error(),
1136 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1137 }
1138 onuLogger.WithFields(log.Fields{
1139 "OnuId": o.ID,
1140 "IntfId": o.PonPortID,
1141 "OnuSn": o.Sn(),
1142 "ActiveImageEntityId": o.ActiveImageEntityId,
1143 "CommittedImageEntityId": o.CommittedImageEntityId,
1144 }).Info("onu-software-image-committed")
1145 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301146 case omci.GetAllAlarmsRequestType:
1147 // Reset the alarm sequence number on receiving get all alarms request.
1148 o.onuAlarmsInfoLock.Lock()
1149 for key, alarmInfo := range o.onuAlarmsInfo {
1150 // reset the alarm sequence no
1151 alarmInfo.SequenceNo = 0
1152 o.onuAlarmsInfo[key] = alarmInfo
1153 }
1154 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001155 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301156 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001157 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301158 responsePkt = nil //Do not send any response for error case
1159 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001160 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001161 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001162 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1163 "omciPkt": msg.OmciPkt,
1164 "omciMsgType": msg.OmciMsg.MessageType,
1165 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001166 "IntfId": o.PonPortID,
1167 "SerialNumber": o.Sn(),
1168 }).Warnf("OMCI-message-not-supported")
1169 }
1170
1171 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001172 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001173 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001174 "IntfId": o.PonPortID,
1175 "SerialNumber": o.Sn(),
1176 "omciPacket": responsePkt,
1177 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1178 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001179 }).Errorf("failed-to-send-omci-message: %v", err)
1180 }
1181 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001182
Pragya Arya324337e2020-02-20 14:35:08 +05301183 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001184 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001185}
Pragya Arya324337e2020-02-20 14:35:08 +05301186
Matteo Scandolof9d43412021-01-12 11:11:34 -08001187// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1188func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1189 indication := &openolt.Indication_OmciInd{
1190 OmciInd: &openolt.OmciIndication{
1191 IntfId: o.PonPortID,
1192 OnuId: o.ID,
1193 Pkt: responsePkt,
1194 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001195 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001196 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1197 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001198 }
1199 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001200 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001201 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001202 "omciPacket": indication.OmciInd.Pkt,
1203 "transCorrId": txId,
1204 }).Trace("omci-message-sent")
1205 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001206}
1207
Matteo Scandolo27428702019-10-11 16:21:16 -07001208func (o *Onu) storePortNumber(portNo uint32) {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001209 // NOTE this needed only as long as we don't support multiple UNIs
Matteo Scandolo27428702019-10-11 16:21:16 -07001210 // we need to add support for multiple UNIs
1211 // the action plan is:
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001212 // - refactor the omcisim-sim library to use https://github.com/cboling/omci instead of canned messages
Matteo Scandolo27428702019-10-11 16:21:16 -07001213 // - change the library so that it reports a single UNI and remove this workaroung
1214 // - add support for multiple UNIs in BBSim
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001215 if o.PortNo == 0 || portNo < o.PortNo {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001216 onuLogger.WithFields(log.Fields{
1217 "IntfId": o.PonPortID,
1218 "OnuId": o.ID,
1219 "SerialNumber": o.Sn(),
1220 "OnuPortNo": o.PortNo,
1221 "FlowPortNo": portNo,
1222 }).Debug("Storing ONU portNo")
Matteo Scandolo27428702019-10-11 16:21:16 -07001223 o.PortNo = portNo
1224 }
1225}
1226
William Kurkian0418bc82019-11-06 12:16:24 -05001227func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001228 onuLogger.WithFields(log.Fields{
1229 "IntfId": o.PonPortID,
1230 "OnuId": id,
1231 "SerialNumber": o.Sn(),
1232 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001233 o.ID = id
1234}
1235
Matteo Scandolof9d43412021-01-12 11:11:34 -08001236func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001237 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001238 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001239 "Cookie": msg.Flow.Cookie,
1240 "DstPort": msg.Flow.Classifier.DstPort,
1241 "FlowId": msg.Flow.FlowId,
1242 "FlowType": msg.Flow.FlowType,
1243 "GemportId": msg.Flow.GemportId,
1244 "InnerVlan": msg.Flow.Classifier.IVid,
1245 "IntfId": msg.Flow.AccessIntfId,
1246 "IpProto": msg.Flow.Classifier.IpProto,
1247 "OnuId": msg.Flow.OnuId,
1248 "OnuSn": o.Sn(),
1249 "OuterVlan": msg.Flow.Classifier.OVid,
1250 "PortNo": msg.Flow.PortNo,
1251 "SrcPort": msg.Flow.Classifier.SrcPort,
1252 "UniID": msg.Flow.UniId,
1253 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1254 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1255 "ClassifierIVid": msg.Flow.Classifier.IVid,
1256 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001257 "ReplicateFlow": msg.Flow.ReplicateFlow,
1258 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001259 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001260
Matteo Scandolo813402b2019-10-23 19:24:52 -07001261 if msg.Flow.UniId != 0 {
1262 // as of now BBSim only support a single UNI, so ignore everything that is not targeted to it
1263 onuLogger.WithFields(log.Fields{
1264 "IntfId": o.PonPortID,
1265 "OnuId": o.ID,
1266 "SerialNumber": o.Sn(),
1267 }).Debug("Ignoring flow as it's not for the first UNI")
1268 return
1269 }
1270
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001271 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001272
1273 var gemPortId uint32
1274 if msg.Flow.ReplicateFlow {
1275 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1276 // first available gemport (we only need to send one packet)
1277 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1278 gemPortId = msg.Flow.PbitToGemport[0]
1279 } else {
1280 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1281 gemPortId = uint32(msg.Flow.GemportId)
1282 }
1283 o.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001284
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001285 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo27428702019-10-11 16:21:16 -07001286 // NOTE storing the PortNO, it's needed when sending PacketIndications
Matteo Scandolo813402b2019-10-23 19:24:52 -07001287 o.storePortNumber(uint32(msg.Flow.PortNo))
Matteo Scandolo4a036262020-08-17 15:56:13 -07001288
1289 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001290 s.HandleAuth()
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001291 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001292 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1293 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001294 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo99f18462019-10-28 14:14:28 -07001295
Matteo Scandolo4a036262020-08-17 15:56:13 -07001296 for _, s := range o.Services {
Matteo Scandolobd875b32020-09-18 17:46:31 -07001297 s.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001298 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001299 }
1300}
1301
Matteo Scandolof9d43412021-01-12 11:11:34 -08001302func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001303 onuLogger.WithFields(log.Fields{
1304 "IntfId": o.PonPortID,
1305 "OnuId": o.ID,
1306 "SerialNumber": o.Sn(),
1307 "FlowId": msg.Flow.FlowId,
1308 "FlowType": msg.Flow.FlowType,
1309 }).Debug("ONU receives FlowRemove")
1310
1311 for idx, flow := range o.FlowIds {
1312 // If the gemport is found, delete it from local cache.
1313 if flow == msg.Flow.FlowId {
1314 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1315 break
1316 }
1317 }
1318
1319 if len(o.FlowIds) == 0 {
1320 onuLogger.WithFields(log.Fields{
1321 "IntfId": o.PonPortID,
1322 "OnuId": o.ID,
1323 "SerialNumber": o.Sn(),
1324 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001325
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301326 // check if ONU delete is performed and
1327 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001328 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301329 close(o.Channel)
1330 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001331 }
1332}
1333
Matteo Scandolocedde462021-03-09 17:37:16 -08001334func (o *Onu) Reboot(timeout time.Duration) error {
1335 onuLogger.WithFields(log.Fields{
1336 "IntfId": o.PonPortID,
1337 "OnuId": o.ID,
1338 "SerialNumber": o.Sn(),
1339 }).Debug("shutting-down-onu")
1340 if err := o.HandleShutdownONU(); err != nil {
1341 return err
1342 }
1343 time.Sleep(timeout)
1344 onuLogger.WithFields(log.Fields{
1345 "IntfId": o.PonPortID,
1346 "OnuId": o.ID,
1347 "SerialNumber": o.Sn(),
1348 }).Debug("power-on-onu")
1349 if err := o.HandlePowerOnONU(); err != nil {
1350 return err
1351 }
1352 return nil
1353}
1354
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001355// BBR methods
1356
1357func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1358 omciMsg := openolt.OmciMsg{
1359 IntfId: intfId,
1360 OnuId: onuId,
1361 Pkt: pktBytes,
1362 }
1363
1364 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1365 log.WithFields(log.Fields{
1366 "IntfId": intfId,
1367 "OnuId": onuId,
1368 "SerialNumber": common.OnuSnToString(sn),
1369 "Pkt": omciMsg.Pkt,
1370 }).Fatalf("Failed to send MIB Reset")
1371 }
1372 log.WithFields(log.Fields{
1373 "IntfId": intfId,
1374 "OnuId": onuId,
1375 "SerialNumber": common.OnuSnToString(sn),
1376 "Pkt": omciMsg.Pkt,
1377 }).Tracef("Sent OMCI message %s", msgType)
1378}
1379
1380func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1381 var next uint16
1382 if len(highPriority) > 0 && highPriority[0] {
1383 next = onu.hpTid
1384 onu.hpTid += 1
1385 if onu.hpTid < 0x8000 {
1386 onu.hpTid = 0x8000
1387 }
1388 } else {
1389 next = onu.tid
1390 onu.tid += 1
1391 if onu.tid >= 0x8000 {
1392 onu.tid = 1
1393 }
1394 }
1395 return next
1396}
1397
1398// TODO move this method in responders/omcisim
1399func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1400 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1401 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1402}
1403
Matteo Scandolof9d43412021-01-12 11:11:34 -08001404// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1405func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1406
1407 // we need to encode the packet in HEX
1408 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1409 hex.Encode(pkt, msg.OmciInd.Pkt)
1410 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1411 if err != nil {
1412 log.WithFields(log.Fields{
1413 "IntfId": o.PonPortID,
1414 "SerialNumber": o.Sn(),
1415 "omciPacket": msg.OmciInd.Pkt,
1416 }).Error("BBR Cannot parse OMCI packet")
1417 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001418
1419 log.WithFields(log.Fields{
1420 "IntfId": msg.OmciInd.IntfId,
1421 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001422 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001423 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001424 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301425 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001426 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001427 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001428 log.WithFields(log.Fields{
1429 "IntfId": msg.OmciInd.IntfId,
1430 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001431 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001432 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001433 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001434 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001435 case omci.MibResetResponseType:
1436 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1437 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1438 case omci.MibUploadResponseType:
1439 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1440 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1441 case omci.MibUploadNextResponseType:
1442 o.seqNumber++
1443
1444 if o.seqNumber > 290 {
1445 // 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 -08001446 // 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 -08001447 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001448 onuLogger.WithFields(log.Fields{
1449 "OnuId": o.ID,
1450 "IntfId": o.PonPortID,
1451 "OnuSn": o.Sn(),
1452 }).Errorf("Error while transitioning ONU State %v", err)
1453 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001454 } else {
1455 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1456 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001457 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001458 }
1459}
1460
1461func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1462
1463 classifierProto := openolt.Classifier{
1464 EthType: uint32(layers.EthernetTypeEAPOL),
1465 OVid: 4091,
1466 }
1467
1468 actionProto := openolt.Action{}
1469
1470 downstreamFlow := openolt.Flow{
1471 AccessIntfId: int32(o.PonPortID),
1472 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001473 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001474 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001475 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001476 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001477 Classifier: &classifierProto,
1478 Action: &actionProto,
1479 Priority: int32(100),
1480 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001481 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1482 // AllocId and GemPorts need to be unique per PON
1483 // for now use the ONU-ID, will need to change once we support multiple UNIs
1484 AllocId: int32(o.ID),
1485 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001486 }
1487
1488 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1489 log.WithFields(log.Fields{
1490 "IntfId": o.PonPortID,
1491 "OnuId": o.ID,
1492 "FlowId": downstreamFlow.FlowId,
1493 "PortNo": downstreamFlow.PortNo,
1494 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001495 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001496 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001497 }
1498 log.WithFields(log.Fields{
1499 "IntfId": o.PonPortID,
1500 "OnuId": o.ID,
1501 "FlowId": downstreamFlow.FlowId,
1502 "PortNo": downstreamFlow.PortNo,
1503 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1504 }).Info("Sent EAPOL Flow")
1505}
1506
1507func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001508
1509 // BBR only works with a single service (ATT HSIA)
1510 hsia := o.Services[0].(*Service)
1511
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001512 classifierProto := openolt.Classifier{
1513 EthType: uint32(layers.EthernetTypeIPv4),
1514 SrcPort: uint32(68),
1515 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001516 OVid: uint32(hsia.CTag),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001517 }
1518
1519 actionProto := openolt.Action{}
1520
1521 downstreamFlow := openolt.Flow{
1522 AccessIntfId: int32(o.PonPortID),
1523 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001524 UniId: int32(0), // FIXME do not hardcode this
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001525 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001526 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001527 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001528 Classifier: &classifierProto,
1529 Action: &actionProto,
1530 Priority: int32(100),
1531 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001532 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1533 // AllocId and GemPorts need to be unique per PON
1534 // for now use the ONU-ID, will need to change once we support multiple UNIs
1535 AllocId: int32(o.ID),
1536 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001537 }
1538
1539 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1540 log.WithFields(log.Fields{
1541 "IntfId": o.PonPortID,
1542 "OnuId": o.ID,
1543 "FlowId": downstreamFlow.FlowId,
1544 "PortNo": downstreamFlow.PortNo,
1545 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001546 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001547 }).Fatalf("Failed to send DHCP Flow")
1548 }
1549 log.WithFields(log.Fields{
1550 "IntfId": o.PonPortID,
1551 "OnuId": o.ID,
1552 "FlowId": downstreamFlow.FlowId,
1553 "PortNo": downstreamFlow.PortNo,
1554 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1555 }).Info("Sent DHCP Flow")
1556}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301557
1558// DeleteFlow method search and delete flowKey from the onu flows slice
1559func (onu *Onu) DeleteFlow(key FlowKey) {
1560 for pos, flowKey := range onu.Flows {
1561 if flowKey == key {
1562 // delete the flowKey by shifting all flowKeys by one
1563 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1564 t := make([]FlowKey, len(onu.Flows))
1565 copy(t, onu.Flows)
1566 onu.Flows = t
1567 break
1568 }
1569 }
1570}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301571
1572func (onu *Onu) ReDiscoverOnu() {
1573 // Wait for few seconds to be sure of the cleanup
1574 time.Sleep(5 * time.Second)
1575
1576 onuLogger.WithFields(log.Fields{
1577 "IntfId": onu.PonPortID,
1578 "OnuId": onu.ID,
1579 "OnuSn": onu.Sn(),
1580 }).Debug("Send ONU Re-Discovery")
1581
1582 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001583 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301584 log.WithFields(log.Fields{
1585 "IntfId": onu.PonPortID,
1586 "OnuSn": onu.Sn(),
1587 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001588 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301589 }
1590
Matteo Scandolocedde462021-03-09 17:37:16 -08001591 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301592 log.WithFields(log.Fields{
1593 "IntfId": onu.PonPortID,
1594 "OnuSn": onu.Sn(),
1595 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001596 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301597 }
1598}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001599
1600func (onu *Onu) addGemPortToService(gemport uint32, ethType uint32, oVlan uint32, iVlan uint32) {
1601 for _, s := range onu.Services {
1602 if service, ok := s.(*Service); ok {
1603 // EAPOL is a strange case, as packets are untagged
1604 // but we assume we will have a single service requiring EAPOL
1605 if ethType == uint32(layers.EthernetTypeEAPOL) && service.NeedsEapol {
1606 service.GemPort = gemport
1607 }
1608
1609 // For DHCP services we single tag the outgoing packets,
1610 // thus the flow only contains the CTag and we can use that to match the service
1611 if ethType == uint32(layers.EthernetTypeIPv4) && service.NeedsDhcp && service.CTag == int(oVlan) {
1612 service.GemPort = gemport
1613 }
1614
1615 // for dataplane services match both C and S tags
1616 if service.CTag == int(iVlan) && service.STag == int(oVlan) {
1617 service.GemPort = gemport
1618 }
1619 }
1620 }
1621}
1622
1623func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
1624 for _, s := range onu.Services {
1625 service := s.(*Service)
1626 if service.HwAddress.String() == macAddress.String() {
1627 return service, nil
1628 }
1629 }
1630 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1631}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301632
1633func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1634 switch alarmType {
1635 case "ONU_ALARM_LOS":
1636 msg := bbsim.Message{
1637 Type: bbsim.UniStatusAlarm,
1638 Data: bbsim.UniStatusAlarmMessage{
1639 OnuSN: o.SerialNumber,
1640 OnuID: o.ID,
1641 EntityID: 257,
1642 RaiseOMCIAlarm: raiseOMCIAlarm,
1643 },
1644 }
1645 o.Channel <- msg
1646 }
1647
1648}
1649
1650func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1651 o.onuAlarmsInfoLock.Lock()
1652 defer o.onuAlarmsInfoLock.Unlock()
1653 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1654 if alarmInfo.SequenceNo == 255 {
1655 alarmInfo.SequenceNo = 1
1656 } else {
1657 alarmInfo.SequenceNo++
1658 }
1659 o.onuAlarmsInfo[key] = alarmInfo
1660 return alarmInfo.SequenceNo
1661 } else {
1662 // This is the first time alarm notification message is being sent
1663 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1664 SequenceNo: 1,
1665 }
1666 return 1
1667 }
1668}