blob: 84706fd15479241c2d3865eadbffc672a23f8bc7 [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
Matteo Scandoloef4e8f82021-05-17 11:20:49 -070055 uniPorts = 4 // TODO this will need to be configurable
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000056)
57
58const (
Matteo Scandolocedde462021-03-09 17:37:16 -080059 // ONU transitions
60 OnuTxInitialize = "initialize"
61 OnuTxDiscover = "discover"
62 OnuTxEnable = "enable"
63 OnuTxDisable = "disable"
64 OnuTxPonDisable = "pon_disable"
65 OnuTxStartImageDownload = "start_image_download"
66 OnuTxProgressImageDownload = "progress_image_download"
67 OnuTxCompleteImageDownload = "complete_image_download"
68 OnuTxFailImageDownload = "fail_image_download"
69 OnuTxActivateImage = "activate_image"
70 OnuTxCommitImage = "commit_image"
71
72 // ONU States
73 OnuStateCreated = "created"
74 OnuStateInitialized = "initialized"
75 OnuStateDiscovered = "discovered"
76 OnuStateEnabled = "enabled"
77 OnuStateDisabled = "disabled"
78 OnuStatePonDisabled = "pon_disabled"
79 OnuStateImageDownloadStarted = "image_download_started"
80 OnuStateImageDownloadInProgress = "image_download_in_progress"
81 OnuStateImageDownloadComplete = "image_download_completed"
82 OnuStateImageDownloadError = "image_download_error"
83 OnuStateImageActivated = "software_image_activated"
84 OnuStateImageCommitted = "software_image_committed"
85
86 // BBR ONU States and Transitions
87 BbrOnuTxSendEapolFlow = "send_eapol_flow"
88 BbrOnuStateEapolFlowSent = "eapol_flow_sent"
89 BbrOnuTxSendDhcpFlow = "send_dhcp_flow"
90 BbrOnuStateDhcpFlowSent = "dhcp_flow_sent"
91)
92
Pragya Arya8bdb4532020-03-02 17:08:09 +053093type FlowKey struct {
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070094 ID uint64
Pragya Arya8bdb4532020-03-02 17:08:09 +053095 Direction string
96}
97
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070098type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -080099 ID uint32
100 PonPortID uint32
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700101 PonPort *PonPort
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800102 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +0530103 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
104 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandolo4a036262020-08-17 15:56:13 -0700105
106 Services []ServiceIf
107
108 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800109 // ONU State
Matteo Scandolo27428702019-10-11 16:21:16 -0700110 // PortNo comes with flows and it's used when sending packetIndications,
111 // There is one PortNo per UNI Port, for now we're only storing the first one
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700112 // FIXME add support for multiple UNIs (each UNI has a different PortNo)
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700113 // deprecated
114 PortNo uint32
115 UniPorts []*UniPort
116 Flows []FlowKey
117 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700118
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700119 OperState *fsm.FSM
120 SerialNumber *openolt.SerialNumber
121
Matteo Scandolof9d43412021-01-12 11:11:34 -0800122 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700123
124 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800125 MibDataSync uint8
126 ImageSoftwareExpectedSections int
127 ImageSoftwareReceivedSections int
128 ActiveImageEntityId uint16
129 CommittedImageEntityId uint16
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000130 OmciResponseRate uint8
131 OmciMsgCounter uint8
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800132
133 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700134 tid uint16
135 hpTid uint16
136 seqNumber uint16
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700137 MibDb *omcilib.MibDb
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700138
Anand S Katti09541352020-01-29 15:54:01 +0530139 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
140 TrafficSchedulers *tech_profile.TrafficSchedulers
Himani Chawla13b1ee02021-03-15 01:43:53 +0530141 onuAlarmsInfoLock sync.RWMutex
142 onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700143}
144
Matteo Scandolo99f18462019-10-28 14:14:28 -0700145func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700146 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700147}
148
Matteo Scandolo4a036262020-08-17 15:56:13 -0700149func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, isMock bool) *Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700150
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700151 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800152 ID: id,
153 PonPortID: pon.ID,
154 PonPort: pon,
155 PortNo: 0,
156 tid: 0x1,
157 hpTid: 0x8000,
158 seqNumber: 0,
159 DoneChannel: make(chan bool, 1),
160 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
161 Flows: []FlowKey{},
162 DiscoveryDelay: delay,
163 MibDataSync: 0,
164 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
165 ImageSoftwareReceivedSections: 0,
166 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
167 CommittedImageEntityId: 0,
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000168 OmciResponseRate: olt.OmciResponseRate,
169 OmciMsgCounter: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700170 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800171 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700172 // NOTE this state machine is used to track the operational
173 // state as requested by VOLTHA
174 o.OperState = getOperStateFSM(func(e *fsm.Event) {
175 onuLogger.WithFields(log.Fields{
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700176 "OnuId": o.ID,
177 "IntfId": o.PonPortID,
178 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700179 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
180 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530181 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700182 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
183 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800184 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700185 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700186 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800187 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
188 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
189 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100190 // 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 -0800191 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530192 // 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 -0800193 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStatePonDisabled},
194 // Software Image Download related states
195 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError}, Dst: OnuStateImageDownloadStarted},
196 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
197 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
198 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
199 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
200 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700201 // BBR States
202 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800203 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
204 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700205 },
206 fsm.Callbacks{
207 "enter_state": func(e *fsm.Event) {
208 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700209 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700210 fmt.Sprintf("enter_%s", OnuStateInitialized): func(e *fsm.Event) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100211 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800212 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800213
Matteo Scandolocedde462021-03-09 17:37:16 -0800214 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800215 onuLogger.WithFields(log.Fields{
216 "OnuId": o.ID,
217 "IntfId": o.PonPortID,
218 "OnuSn": o.Sn(),
219 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
220 }
221
Pragya Arya1cbefa42020-01-13 12:15:29 +0530222 if !isMock {
223 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700224 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530225 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100226 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700227 fmt.Sprintf("enter_%s", OnuStateDiscovered): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800228 msg := bbsim.Message{
229 Type: bbsim.OnuDiscIndication,
230 Data: bbsim.OnuDiscIndicationMessage{
231 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100232 },
233 }
234 o.Channel <- msg
235 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700236 fmt.Sprintf("enter_%s", OnuStateEnabled): func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800237
238 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
239 onuLogger.WithFields(log.Fields{
240 "IntfId": o.PonPortID,
241 "OnuId": o.ID,
242 "SerialNumber": o.Sn(),
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700243 }).Errorf("onu-id-duplicated-with-%s", common.OnuSnToString(sn))
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800244 return
245 } else {
246 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
247 }
248
Matteo Scandolof9d43412021-01-12 11:11:34 -0800249 msg := bbsim.Message{
250 Type: bbsim.OnuIndication,
251 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700252 OnuSN: o.SerialNumber,
253 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800254 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700255 },
256 }
257 o.Channel <- msg
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700258
259 // Once the ONU is enabled start listening for packets
260 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700261 s.Initialize(o.PonPort.Olt.OpenoltStream)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700262 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700263 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700264 fmt.Sprintf("enter_%s", OnuStateDisabled): func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700265
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700266 o.cleanupOnuState()
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700267
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700268 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800269 if err := o.OperState.Event("disable"); err != nil {
270 onuLogger.WithFields(log.Fields{
271 "OnuId": o.ID,
272 "IntfId": o.PonPortID,
273 "OnuSn": o.Sn(),
274 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
275 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700276 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800277 msg := bbsim.Message{
278 Type: bbsim.OnuIndication,
279 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700280 OnuSN: o.SerialNumber,
281 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800282 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700283 },
284 }
285 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530286
287 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100288 // terminate the ONU's ProcessOnuMessages Go routine
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530289 if len(o.FlowIds) == 0 {
290 close(o.Channel)
291 }
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700292
293 for _, s := range o.Services {
294 s.Disable()
295 }
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700296
297 },
298 fmt.Sprintf("enter_%s", OnuStatePonDisabled): func(event *fsm.Event) {
299 o.cleanupOnuState()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700300 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700301 // BBR states
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700302 fmt.Sprintf("enter_%s", BbrOnuStateEapolFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800303 msg := bbsim.Message{
304 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700305 }
306 o.Channel <- msg
307 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700308 fmt.Sprintf("enter_%s", BbrOnuStateDhcpFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800309 msg := bbsim.Message{
310 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700311 }
312 o.Channel <- msg
313 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700314 },
315 )
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100316
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700317 for i := 0; i < uniPorts; i++ {
318 uni, err := NewUniPort(uint32(i), &o)
319 if err != nil {
320 onuLogger.WithFields(log.Fields{
321 "OnuId": o.ID,
322 "IntfId": o.PonPortID,
323 "OnuSn": o.Sn(),
324 "Err": err,
325 }).Fatal("cannot-create-uni-port")
326 }
327 o.UniPorts = append(o.UniPorts, uni)
328 }
329
330 mibDb, err := omcilib.GenerateMibDatabase(len(o.UniPorts))
331 if err != nil {
332 onuLogger.WithFields(log.Fields{
333 "OnuId": o.ID,
334 "IntfId": o.PonPortID,
335 "OnuSn": o.Sn(),
336 }).Fatal("cannot-generate-mibdb-for-onu")
337 }
338 o.MibDb = mibDb
339
Matteo Scandolo27428702019-10-11 16:21:16 -0700340 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700341}
342
William Kurkian0418bc82019-11-06 12:16:24 -0500343func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700344 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700345 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700346 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700347 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700348 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
349}
350
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700351// cleanupOnuState this method is to clean the local state when the ONU is disabled
352func (o *Onu) cleanupOnuState() {
353 // clean the ONU state
354 o.PortNo = 0
355 o.Flows = []FlowKey{}
356 o.PonPort.removeOnuId(o.ID)
357 o.PonPort.removeAllocId(o.SerialNumber)
358 o.PonPort.removeGemPortBySn(o.SerialNumber)
359
360 o.onuAlarmsInfoLock.Lock()
361 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
362 o.onuAlarmsInfoLock.Unlock()
363}
364
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100365// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000366func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700367 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100368 "onuID": o.ID,
369 "onuSN": o.Sn(),
370 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700371 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100372 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700373
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700374 defer onuLogger.WithFields(log.Fields{
375 "onuID": o.ID,
376 "onuSN": o.Sn(),
377 "stream": stream,
378 }).Debug("Stopped handling ONU Indication Channel")
379
David Bainbridge103cf022019-12-16 20:11:35 +0000380loop:
381 for {
382 select {
383 case <-ctx.Done():
384 onuLogger.WithFields(log.Fields{
385 "onuID": o.ID,
386 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700387 }).Debug("ONU message handling canceled via context")
388 break loop
389 case <-stream.Context().Done():
390 onuLogger.WithFields(log.Fields{
391 "onuID": o.ID,
392 "onuSN": o.Sn(),
393 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000394 break loop
395 case message, ok := <-o.Channel:
396 if !ok || ctx.Err() != nil {
397 onuLogger.WithFields(log.Fields{
398 "onuID": o.ID,
399 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700400 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000401 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700402 }
David Bainbridge103cf022019-12-16 20:11:35 +0000403 onuLogger.WithFields(log.Fields{
404 "onuID": o.ID,
405 "onuSN": o.Sn(),
406 "messageType": message.Type,
407 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700408
David Bainbridge103cf022019-12-16 20:11:35 +0000409 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800410 case bbsim.OnuDiscIndication:
411 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000412 // 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 +0530413 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000414 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800415 case bbsim.OnuIndication:
416 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000417 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800418 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800419 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800420 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200421 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800422 case bbsim.UniStatusAlarm:
423 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530424 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
425 MeInstance: msg.EntityID,
426 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
427 }
428 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
429 o.onuAlarmsInfoLock.Lock()
430 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
431 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
432 if pkt != nil { //pkt will be nil if we are unable to create the alarm
433 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
434 onuLogger.WithFields(log.Fields{
435 "IntfId": o.PonPortID,
436 "SerialNumber": o.Sn(),
437 "omciPacket": pkt,
438 "adminState": msg.AdminState,
439 "entityID": msg.EntityID,
440 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
441 alarmInfo.SequenceNo--
442 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800443 onuLogger.WithFields(log.Fields{
444 "IntfId": o.PonPortID,
445 "SerialNumber": o.Sn(),
446 "omciPacket": pkt,
447 "adminState": msg.AdminState,
448 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530449 }).Trace("UNI-Link-alarm-sent")
450 if alarmBitMap == [28]byte{0} {
451 delete(o.onuAlarmsInfo, onuAlarmMapKey)
452 } else {
453 alarmInfo.AlarmBitMap = alarmBitMap
454 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
455 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800456 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530457 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800458 case bbsim.FlowAdd:
459 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700460 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800461 case bbsim.FlowRemoved:
462 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700463 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800464 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700465
Matteo Scandolof9d43412021-01-12 11:11:34 -0800466 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000467
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700468 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000469 "IntfId": msg.IntfId,
470 "OnuId": msg.OnuId,
471 "pktType": msg.Type,
472 }).Trace("Received OnuPacketOut Message")
473
Matteo Scandolo618a6582020-09-09 12:21:29 -0700474 if msg.Type == packetHandlers.EAPOL || msg.Type == packetHandlers.DHCP {
475
476 service, err := o.findServiceByMacAddress(msg.MacAddress)
477 if err != nil {
478 onuLogger.WithFields(log.Fields{
479 "IntfId": msg.IntfId,
480 "OnuId": msg.OnuId,
481 "pktType": msg.Type,
482 "MacAddress": msg.MacAddress,
483 "Pkt": hex.EncodeToString(msg.Packet.Data()),
484 "OnuSn": o.Sn(),
485 }).Error("Cannot find Service associated with packet")
486 return
487 }
488 service.PacketCh <- msg
489 } else if msg.Type == packetHandlers.IGMP {
490 // if it's an IGMP packet we assume we have a single IGMP service
491 for _, s := range o.Services {
492 service := s.(*Service)
493
494 if service.NeedsIgmp {
495 service.PacketCh <- msg
496 }
497 }
David Bainbridge103cf022019-12-16 20:11:35 +0000498 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700499
Matteo Scandolof9d43412021-01-12 11:11:34 -0800500 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000501 // NOTE we only receive BBR packets here.
502 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
503 // 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 -0800504 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000505
506 log.WithFields(log.Fields{
507 "IntfId": msg.IntfId,
508 "OnuId": msg.OnuId,
509 "pktType": msg.Type,
510 }).Trace("Received OnuPacketIn Message")
511
512 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700513 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 +0000514 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700515 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000516 }
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700517 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800518 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800519 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800520 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
521 o.handleOmciResponse(msg, client)
522 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000523 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800524 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000525 o.sendDhcpFlow(client)
526 default:
527 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700528 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700529 }
530 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700531}
532
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800533func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700534 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700535 sn.VendorId = []byte("BBSM")
536 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700537 return sn
538}
539
Matteo Scandolof9d43412021-01-12 11:11:34 -0800540func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700541 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800542 IntfId: o.PonPortID,
543 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700544 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700545
Matteo Scandolo4747d292019-08-05 11:50:18 -0700546 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700547 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700548 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700549 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700550
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700551 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800552 "IntfId": o.PonPortID,
553 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700554 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700555 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800556 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800557
558 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
559 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800560 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800561 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800562 o.sendOnuDiscIndication(msg, stream)
563 }
564 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700565}
566
Matteo Scandolof9d43412021-01-12 11:11:34 -0800567func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800568 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
569 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700570
571 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700572 IntfId: o.PonPortID,
573 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700574 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700575 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700576 SerialNumber: o.SerialNumber,
577 }}
578 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800579 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700580 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700581 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700582 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700583 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800584 "IntfId": o.PonPortID,
585 "OnuId": o.ID,
586 "VolthaOnuId": msg.OnuID,
587 "OperState": msg.OperState.String(),
588 "AdminState": msg.OperState.String(),
589 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700590 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700591
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700592}
593
Matteo Scandolof9d43412021-01-12 11:11:34 -0800594func (o *Onu) HandleShutdownONU() error {
595
596 dyingGasp := pb.ONUAlarmRequest{
597 AlarmType: "DYING_GASP",
598 SerialNumber: o.Sn(),
599 Status: "on",
600 }
601
602 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
603 onuLogger.WithFields(log.Fields{
604 "OnuId": o.ID,
605 "IntfId": o.PonPortID,
606 "OnuSn": o.Sn(),
607 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
608 return err
609 }
610
611 losReq := pb.ONUAlarmRequest{
612 AlarmType: "ONU_ALARM_LOS",
613 SerialNumber: o.Sn(),
614 Status: "on",
615 }
616
617 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
618 onuLogger.WithFields(log.Fields{
619 "OnuId": o.ID,
620 "IntfId": o.PonPortID,
621 "OnuSn": o.Sn(),
622 }).Errorf("Cannot send LOS: %s", err.Error())
623
624 return err
625 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530626 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800627 // TODO if it's the last ONU on the PON, then send a PON LOS
628
Matteo Scandolocedde462021-03-09 17:37:16 -0800629 if err := o.InternalState.Event(OnuTxDisable); 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 shutdown ONU: %s", err.Error())
635 return err
636 }
637
638 return nil
639}
640
641func (o *Onu) HandlePowerOnONU() error {
642 intitalState := o.InternalState.Current()
643
644 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800645 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
646 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800647 onuLogger.WithFields(log.Fields{
648 "OnuId": o.ID,
649 "IntfId": o.PonPortID,
650 "OnuSn": o.Sn(),
651 }).Errorf("Cannot poweron ONU: %s", err.Error())
652 return err
653 }
654 }
655
656 // turn off the LOS Alarm
657 losReq := pb.ONUAlarmRequest{
658 AlarmType: "ONU_ALARM_LOS",
659 SerialNumber: o.Sn(),
660 Status: "off",
661 }
662
663 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
664 onuLogger.WithFields(log.Fields{
665 "OnuId": o.ID,
666 "IntfId": o.PonPortID,
667 "OnuSn": o.Sn(),
668 }).Errorf("Cannot send LOS: %s", err.Error())
669 return err
670 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530671 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800672
673 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800674 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800675 onuLogger.WithFields(log.Fields{
676 "OnuId": o.ID,
677 "IntfId": o.PonPortID,
678 "OnuSn": o.Sn(),
679 }).Errorf("Cannot poweron ONU: %s", err.Error())
680 return err
681 }
682
683 // move o directly to enable state only when its a powercycle case
684 // in case of first time o poweron o will be moved to enable on
685 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800686 if intitalState == OnuStateDisabled {
687 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800688 onuLogger.WithFields(log.Fields{
689 "OnuId": o.ID,
690 "IntfId": o.PonPortID,
691 "OnuSn": o.Sn(),
692 }).Errorf("Cannot enable ONU: %s", err.Error())
693 return err
694 }
695 }
696
697 return nil
698}
699
700func (o *Onu) SetAlarm(alarmType string, status string) error {
701 alarmReq := pb.ONUAlarmRequest{
702 AlarmType: alarmType,
703 SerialNumber: o.Sn(),
704 Status: status,
705 }
706
707 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
708 if err != nil {
709 return err
710 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530711 raiseAlarm := false
712 if alarmReq.Status == "on" {
713 raiseAlarm = true
714 }
715 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800716 return nil
717}
718
719func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530720 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700721 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530722 if err != nil {
723 log.Errorf("error in getting msgType %v", err)
724 return
725 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800726 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530727 o.seqNumber = 0
728 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800729 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530730 o.seqNumber++
731 if o.seqNumber > 290 {
732 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
733 }
734 }
735 }
736}
737
Matteo Scandolof9d43412021-01-12 11:11:34 -0800738// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
739// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200740func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800741
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700742 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700743 "omciMsgType": msg.OmciMsg.MessageType,
744 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
745 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700746 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700747 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800748 }).Trace("omci-message-decoded")
749
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000750 if o.OmciMsgCounter < maxOmciMsgCounter {
751 o.OmciMsgCounter++
752 } else {
753 o.OmciMsgCounter = 1
754 }
755 if o.OmciMsgCounter > o.OmciResponseRate {
756 onuLogger.WithFields(log.Fields{
757 "OmciMsgCounter": o.OmciMsgCounter,
758 "OmciResponseRate": o.OmciResponseRate,
759 "omciMsgType": msg.OmciMsg.MessageType,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200760 }).Debug("skipping-omci-msg-response")
761 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000762 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800763 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800764 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700765 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800766 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800767 onuLogger.WithFields(log.Fields{
768 "IntfId": o.PonPortID,
769 "OnuId": o.ID,
770 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700771 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700772 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800773 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700774
775 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
776 o.PonPort.removeAllocId(o.SerialNumber)
777 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800778 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800779 case omci.MibUploadRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700780 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800781 case omci.MibUploadNextRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700782 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800783 case omci.GetRequestType:
Girish Gowdra996d81e2021-04-21 16:16:27 -0700784 onuDown := o.OperState.Current() == "down"
785 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId, o.CommittedImageEntityId, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800786 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800787 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700788 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800789 switch msgObj.EntityClass {
790 case me.PhysicalPathTerminationPointEthernetUniClassID:
791 // if we're Setting a PPTP state
792 // we need to send the appropriate alarm
793
794 if msgObj.EntityInstance == 257 {
795 // for now we're only caring about the first UNI
796 // NOTE that the EntityID for the UNI port is for now hardcoded in
797 // omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
798 // are reported during the MIB Upload sequence
799 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530800 raiseOMCIAlarm := false
801 if adminState == 1 {
802 raiseOMCIAlarm = true
Girish Gowdra996d81e2021-04-21 16:16:27 -0700803 // set the OperState to disabled
804 if err := o.OperState.Event(OnuTxDisable); err != nil {
805 onuLogger.WithFields(log.Fields{
806 "OnuId": o.ID,
807 "IntfId": o.PonPortID,
808 "OnuSn": o.Sn(),
809 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
810 }
811 } else {
812 // set the OperState to enabled
813 if err := o.OperState.Event(OnuTxEnable); err != nil {
814 onuLogger.WithFields(log.Fields{
815 "OnuId": o.ID,
816 "IntfId": o.PonPortID,
817 "OnuSn": o.Sn(),
818 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
819 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530820 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800821 msg := bbsim.Message{
822 Type: bbsim.UniStatusAlarm,
823 Data: bbsim.UniStatusAlarmMessage{
Himani Chawla13b1ee02021-03-15 01:43:53 +0530824 OnuSN: o.SerialNumber,
825 OnuID: o.ID,
826 AdminState: adminState,
827 EntityID: msgObj.EntityInstance,
828 RaiseOMCIAlarm: raiseOMCIAlarm,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800829 },
830 }
831 o.Channel <- msg
832 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800833 case me.TContClassID:
834 allocId := msgObj.Attributes["AllocId"].(uint16)
835
836 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
837 // otherwise we are adding it
838 if allocId == 255 || allocId == 65535 {
839 onuLogger.WithFields(log.Fields{
840 "IntfId": o.PonPortID,
841 "OnuId": o.ID,
842 "TContId": msgObj.EntityInstance,
843 "AllocId": allocId,
844 "SerialNumber": o.Sn(),
845 }).Trace("freeing-alloc-id-via-omci")
846 o.PonPort.removeAllocId(o.SerialNumber)
847 } else {
848 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
849 onuLogger.WithFields(log.Fields{
850 "IntfId": o.PonPortID,
851 "OnuId": o.ID,
852 "AllocId": allocId,
853 "SerialNumber": o.Sn(),
854 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
855 success = false
856 } else {
857 onuLogger.WithFields(log.Fields{
858 "IntfId": o.PonPortID,
859 "OnuId": o.ID,
860 "TContId": msgObj.EntityInstance,
861 "AllocId": allocId,
862 "SerialNumber": o.Sn(),
863 }).Trace("storing-alloc-id-via-omci")
864 o.PonPort.storeAllocId(allocId, o.SerialNumber)
865 }
866 }
867
868 }
869
870 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700871 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800872 o.MibDataSync++
873 }
874 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700875 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800876 }
877 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800878 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
879 var used bool
880 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700881 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800882 if err == nil {
883 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700884 // GemPort 4069 is reserved for multicast and shared across ONUs
885 if msgObj.EntityInstance != 4069 {
886 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
887 onuLogger.WithFields(log.Fields{
888 "IntfId": o.PonPortID,
889 "OnuId": o.ID,
890 "GemPortId": msgObj.EntityInstance,
891 "SerialNumber": o.Sn(),
892 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
893 } else {
894 onuLogger.WithFields(log.Fields{
895 "IntfId": o.PonPortID,
896 "OnuId": o.ID,
897 "GemPortId": msgObj.EntityInstance,
898 "SerialNumber": o.Sn(),
899 }).Trace("storing-gem-port-id-via-omci")
900 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
901 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800902 }
903 }
904 }
905
906 // if the gemPort is valid then increment the MDS and return a successful response
907 // otherwise fail the request
908 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
909 // validation this check will need to be rewritten
910 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700911 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800912 o.MibDataSync++
913 }
914 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700915 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800916 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800917 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700918 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800919 if err == nil {
920 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
921 onuLogger.WithFields(log.Fields{
922 "IntfId": o.PonPortID,
923 "OnuId": o.ID,
924 "GemPortId": msgObj.EntityInstance,
925 "SerialNumber": o.Sn(),
926 }).Trace("freeing-gem-port-id-via-omci")
927 o.PonPort.removeGemPort(msgObj.EntityInstance)
928 }
929 }
930
Matteo Scandolob5913142021-03-19 16:10:18 -0700931 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800932 o.MibDataSync++
933 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800934 case omci.RebootRequestType:
935
Matteo Scandolob5913142021-03-19 16:10:18 -0700936 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800937
938 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800939 // we run this in a separate goroutine so that
940 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800941 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800942 if err := o.Reboot(10 * time.Second); err != nil {
943 log.WithFields(log.Fields{
944 "IntfId": o.PonPortID,
945 "OnuId": o.ID,
946 "SerialNumber": o.Sn(),
947 "err": err,
948 }).Error("cannot-reboot-onu-after-omci-reboot-request")
949 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800950 }()
951 case omci.TestRequestType:
Girish Gowdra161d27a2021-05-05 12:01:44 -0700952 var classID me.ClassID
953 var omciResult me.Results
954 var instID uint16
955 responsePkt, errResp, classID, instID, omciResult = omcilib.CreateTestResponse(msg.OmciPkt, msg.OmciMsg)
956 // Send TestResult only in case the TestResponse omci result code is me.Success
957 if responsePkt != nil && errResp == nil && omciResult == me.Success {
958 if testResultPkt, err := omcilib.CreateTestResult(classID, instID, msg.OmciMsg.TransactionID); err == nil {
959 // send test results asynchronously
960 go func() {
961 // Send test results after a second to emulate async behavior
962 time.Sleep(1 * time.Second)
963 if testResultPkt != nil {
964 if err := o.sendOmciIndication(testResultPkt, msg.OmciMsg.TransactionID, stream); err != nil {
965 onuLogger.WithFields(log.Fields{
966 "IntfId": o.PonPortID,
967 "SerialNumber": o.Sn(),
968 "omciPacket": testResultPkt,
969 "msg.OmciMsgType": msg.OmciMsg.MessageType,
970 "transCorrId": msg.OmciMsg.TransactionID,
971 }).Errorf("failed-to-send-omci-message: %v", err)
972 }
973 }
974 }()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800975 }
976 }
Girish Gowdraa539f522021-02-15 23:00:45 -0800977 case omci.SynchronizeTimeRequestType:
978 // MDS counter increment is not required for this message type
Matteo Scandolob5913142021-03-19 16:10:18 -0700979 responsePkt, _ = omcilib.CreateSyncTimeResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -0800980 case omci.StartSoftwareDownloadRequestType:
981
982 o.ImageSoftwareReceivedSections = 0
983
Matteo Scandolob5913142021-03-19 16:10:18 -0700984 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
Matteo Scandolocedde462021-03-09 17:37:16 -0800985
Matteo Scandolob5913142021-03-19 16:10:18 -0700986 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -0800987 o.MibDataSync++
988 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
989 onuLogger.WithFields(log.Fields{
990 "OnuId": o.ID,
991 "IntfId": o.PonPortID,
992 "OnuSn": o.Sn(),
993 "Err": err.Error(),
994 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
995 }
996 } else {
997 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700998 "OmciMsgType": msg.OmciMsg.MessageType,
999 "TransCorrId": msg.OmciMsg.TransactionID,
1000 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001001 "IntfId": o.PonPortID,
1002 "SerialNumber": o.Sn(),
1003 }).Error("error-while-processing-start-software-download-request")
1004 }
1005 case omci.DownloadSectionRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001006 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001007 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001008 "OmciMsgType": msg.OmciMsg.MessageType,
1009 "TransCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001010 "EntityInstance": msgObj.EntityInstance,
1011 "SectionNumber": msgObj.SectionNumber,
1012 "SectionData": msgObj.SectionData,
1013 }).Trace("received-download-section-request")
1014 o.ImageSoftwareReceivedSections++
1015 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1016 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1017 onuLogger.WithFields(log.Fields{
1018 "OnuId": o.ID,
1019 "IntfId": o.PonPortID,
1020 "OnuSn": o.Sn(),
1021 "Err": err.Error(),
1022 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1023 }
1024 }
1025 }
1026 case omci.DownloadSectionRequestWithResponseType:
1027 // NOTE we only need to respond if an ACK is requested
Matteo Scandolob5913142021-03-19 16:10:18 -07001028 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1029 if errResp != nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001030 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001031 "OmciMsgType": msg.OmciMsg.MessageType,
1032 "TransCorrId": msg.OmciMsg.TransactionID,
1033 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001034 "IntfId": o.PonPortID,
1035 "SerialNumber": o.Sn(),
1036 }).Error("error-while-processing-create-download-section-response")
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001037 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
Matteo Scandolocedde462021-03-09 17:37:16 -08001038 }
1039 o.ImageSoftwareReceivedSections++
1040
1041 case omci.EndSoftwareDownloadRequestType:
1042
1043 // In the startSoftwareDownload we get the image size and the window size.
1044 // We calculate how many DownloadSection we should receive and validate
1045 // that we got the correct amount when we receive this message
1046 success := true
1047 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1048 onuLogger.WithFields(log.Fields{
1049 "OnuId": o.ID,
1050 "IntfId": o.PonPortID,
1051 "OnuSn": o.Sn(),
1052 "ExpectedSections": o.ImageSoftwareExpectedSections,
1053 "ReceivedSections": o.ImageSoftwareReceivedSections,
1054 }).Errorf("onu-did-not-receive-all-image-sections")
1055 success = false
1056 }
1057
1058 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001059 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001060 o.MibDataSync++
1061 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1062 onuLogger.WithFields(log.Fields{
1063 "OnuId": o.ID,
1064 "IntfId": o.PonPortID,
1065 "OnuSn": o.Sn(),
1066 "Err": err.Error(),
1067 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1068 }
1069 } else {
1070 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001071 "OmciMsgType": msg.OmciMsg.MessageType,
1072 "TransCorrId": msg.OmciMsg.TransactionID,
1073 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001074 "IntfId": o.PonPortID,
1075 "SerialNumber": o.Sn(),
1076 }).Error("error-while-processing-end-software-download-request")
1077 }
1078 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001079 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001080 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1081 onuLogger.WithFields(log.Fields{
1082 "OnuId": o.ID,
1083 "IntfId": o.PonPortID,
1084 "OnuSn": o.Sn(),
1085 "Err": err.Error(),
1086 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1087 }
1088 }
1089 }
1090
1091 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001092 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001093 o.MibDataSync++
1094 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1095 onuLogger.WithFields(log.Fields{
1096 "OnuId": o.ID,
1097 "IntfId": o.PonPortID,
1098 "OnuSn": o.Sn(),
1099 "Err": err.Error(),
1100 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1101 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001102 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001103 o.ActiveImageEntityId = msgObj.EntityInstance
1104 } else {
1105 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1106 }
1107 onuLogger.WithFields(log.Fields{
1108 "OnuId": o.ID,
1109 "IntfId": o.PonPortID,
1110 "OnuSn": o.Sn(),
1111 "ActiveImageEntityId": o.ActiveImageEntityId,
1112 "CommittedImageEntityId": o.CommittedImageEntityId,
1113 }).Info("onu-software-image-activated")
1114
1115 // powercycle the ONU
1116 // we run this in a separate goroutine so that
1117 // the ActivateSoftwareResponse is sent to VOLTHA
1118 // NOTE do we need to wait before rebooting?
1119 go func() {
1120 if err := o.Reboot(10 * time.Second); err != nil {
1121 log.WithFields(log.Fields{
1122 "IntfId": o.PonPortID,
1123 "OnuId": o.ID,
1124 "SerialNumber": o.Sn(),
1125 "err": err,
1126 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1127 }
1128 }()
1129 }
1130 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001131 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001132 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001133 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001134 // TODO validate that the image to commit is:
1135 // - active
1136 // - not already committed
1137 o.CommittedImageEntityId = msgObj.EntityInstance
1138 } else {
1139 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1140 }
1141 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1142 onuLogger.WithFields(log.Fields{
1143 "OnuId": o.ID,
1144 "IntfId": o.PonPortID,
1145 "OnuSn": o.Sn(),
1146 "Err": err.Error(),
1147 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1148 }
1149 onuLogger.WithFields(log.Fields{
1150 "OnuId": o.ID,
1151 "IntfId": o.PonPortID,
1152 "OnuSn": o.Sn(),
1153 "ActiveImageEntityId": o.ActiveImageEntityId,
1154 "CommittedImageEntityId": o.CommittedImageEntityId,
1155 }).Info("onu-software-image-committed")
1156 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301157 case omci.GetAllAlarmsRequestType:
1158 // Reset the alarm sequence number on receiving get all alarms request.
1159 o.onuAlarmsInfoLock.Lock()
1160 for key, alarmInfo := range o.onuAlarmsInfo {
1161 // reset the alarm sequence no
1162 alarmInfo.SequenceNo = 0
1163 o.onuAlarmsInfo[key] = alarmInfo
1164 }
1165 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001166 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301167 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001168 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301169 responsePkt = nil //Do not send any response for error case
1170 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001171 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001172 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001173 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1174 "omciPkt": msg.OmciPkt,
1175 "omciMsgType": msg.OmciMsg.MessageType,
1176 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001177 "IntfId": o.PonPortID,
1178 "SerialNumber": o.Sn(),
1179 }).Warnf("OMCI-message-not-supported")
1180 }
1181
1182 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001183 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001184 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001185 "IntfId": o.PonPortID,
1186 "SerialNumber": o.Sn(),
1187 "omciPacket": responsePkt,
1188 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1189 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001190 }).Errorf("failed-to-send-omci-message: %v", err)
1191 }
1192 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001193
Pragya Arya324337e2020-02-20 14:35:08 +05301194 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001195 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001196}
Pragya Arya324337e2020-02-20 14:35:08 +05301197
Matteo Scandolof9d43412021-01-12 11:11:34 -08001198// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1199func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1200 indication := &openolt.Indication_OmciInd{
1201 OmciInd: &openolt.OmciIndication{
1202 IntfId: o.PonPortID,
1203 OnuId: o.ID,
1204 Pkt: responsePkt,
1205 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001206 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001207 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1208 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001209 }
1210 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001211 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001212 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001213 "omciPacket": indication.OmciInd.Pkt,
1214 "transCorrId": txId,
1215 }).Trace("omci-message-sent")
1216 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001217}
1218
Matteo Scandolo27428702019-10-11 16:21:16 -07001219func (o *Onu) storePortNumber(portNo uint32) {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001220 // NOTE this needed only as long as we don't support multiple UNIs
Matteo Scandolo27428702019-10-11 16:21:16 -07001221 // we need to add support for multiple UNIs
1222 // the action plan is:
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001223 // - refactor the omcisim-sim library to use https://github.com/cboling/omci instead of canned messages
Matteo Scandolo27428702019-10-11 16:21:16 -07001224 // - change the library so that it reports a single UNI and remove this workaroung
1225 // - add support for multiple UNIs in BBSim
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001226 if o.PortNo == 0 || portNo < o.PortNo {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001227 onuLogger.WithFields(log.Fields{
1228 "IntfId": o.PonPortID,
1229 "OnuId": o.ID,
1230 "SerialNumber": o.Sn(),
1231 "OnuPortNo": o.PortNo,
1232 "FlowPortNo": portNo,
1233 }).Debug("Storing ONU portNo")
Matteo Scandolo27428702019-10-11 16:21:16 -07001234 o.PortNo = portNo
1235 }
1236}
1237
William Kurkian0418bc82019-11-06 12:16:24 -05001238func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001239 onuLogger.WithFields(log.Fields{
1240 "IntfId": o.PonPortID,
1241 "OnuId": id,
1242 "SerialNumber": o.Sn(),
1243 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001244 o.ID = id
1245}
1246
Matteo Scandolof9d43412021-01-12 11:11:34 -08001247func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001248 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001249 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001250 "Cookie": msg.Flow.Cookie,
1251 "DstPort": msg.Flow.Classifier.DstPort,
1252 "FlowId": msg.Flow.FlowId,
1253 "FlowType": msg.Flow.FlowType,
1254 "GemportId": msg.Flow.GemportId,
1255 "InnerVlan": msg.Flow.Classifier.IVid,
1256 "IntfId": msg.Flow.AccessIntfId,
1257 "IpProto": msg.Flow.Classifier.IpProto,
1258 "OnuId": msg.Flow.OnuId,
1259 "OnuSn": o.Sn(),
1260 "OuterVlan": msg.Flow.Classifier.OVid,
1261 "PortNo": msg.Flow.PortNo,
1262 "SrcPort": msg.Flow.Classifier.SrcPort,
1263 "UniID": msg.Flow.UniId,
1264 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1265 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1266 "ClassifierIVid": msg.Flow.Classifier.IVid,
1267 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001268 "ReplicateFlow": msg.Flow.ReplicateFlow,
1269 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001270 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001271
Matteo Scandolo813402b2019-10-23 19:24:52 -07001272 if msg.Flow.UniId != 0 {
1273 // as of now BBSim only support a single UNI, so ignore everything that is not targeted to it
1274 onuLogger.WithFields(log.Fields{
1275 "IntfId": o.PonPortID,
1276 "OnuId": o.ID,
1277 "SerialNumber": o.Sn(),
1278 }).Debug("Ignoring flow as it's not for the first UNI")
1279 return
1280 }
1281
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001282 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001283
1284 var gemPortId uint32
1285 if msg.Flow.ReplicateFlow {
1286 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1287 // first available gemport (we only need to send one packet)
1288 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1289 gemPortId = msg.Flow.PbitToGemport[0]
1290 } else {
1291 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1292 gemPortId = uint32(msg.Flow.GemportId)
1293 }
1294 o.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001295
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001296 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo27428702019-10-11 16:21:16 -07001297 // NOTE storing the PortNO, it's needed when sending PacketIndications
Matteo Scandolo813402b2019-10-23 19:24:52 -07001298 o.storePortNumber(uint32(msg.Flow.PortNo))
Matteo Scandolo4a036262020-08-17 15:56:13 -07001299
1300 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001301 s.HandleAuth()
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001302 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001303 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1304 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001305 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo99f18462019-10-28 14:14:28 -07001306
Matteo Scandolo4a036262020-08-17 15:56:13 -07001307 for _, s := range o.Services {
Matteo Scandolobd875b32020-09-18 17:46:31 -07001308 s.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001309 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001310 }
1311}
1312
Matteo Scandolof9d43412021-01-12 11:11:34 -08001313func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001314 onuLogger.WithFields(log.Fields{
1315 "IntfId": o.PonPortID,
1316 "OnuId": o.ID,
1317 "SerialNumber": o.Sn(),
1318 "FlowId": msg.Flow.FlowId,
1319 "FlowType": msg.Flow.FlowType,
1320 }).Debug("ONU receives FlowRemove")
1321
1322 for idx, flow := range o.FlowIds {
1323 // If the gemport is found, delete it from local cache.
1324 if flow == msg.Flow.FlowId {
1325 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1326 break
1327 }
1328 }
1329
1330 if len(o.FlowIds) == 0 {
1331 onuLogger.WithFields(log.Fields{
1332 "IntfId": o.PonPortID,
1333 "OnuId": o.ID,
1334 "SerialNumber": o.Sn(),
1335 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001336
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301337 // check if ONU delete is performed and
1338 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001339 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301340 close(o.Channel)
1341 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001342 }
1343}
1344
Matteo Scandolocedde462021-03-09 17:37:16 -08001345func (o *Onu) Reboot(timeout time.Duration) error {
1346 onuLogger.WithFields(log.Fields{
1347 "IntfId": o.PonPortID,
1348 "OnuId": o.ID,
1349 "SerialNumber": o.Sn(),
1350 }).Debug("shutting-down-onu")
1351 if err := o.HandleShutdownONU(); err != nil {
1352 return err
1353 }
1354 time.Sleep(timeout)
1355 onuLogger.WithFields(log.Fields{
1356 "IntfId": o.PonPortID,
1357 "OnuId": o.ID,
1358 "SerialNumber": o.Sn(),
1359 }).Debug("power-on-onu")
1360 if err := o.HandlePowerOnONU(); err != nil {
1361 return err
1362 }
1363 return nil
1364}
1365
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001366// BBR methods
1367
1368func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1369 omciMsg := openolt.OmciMsg{
1370 IntfId: intfId,
1371 OnuId: onuId,
1372 Pkt: pktBytes,
1373 }
1374
1375 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1376 log.WithFields(log.Fields{
1377 "IntfId": intfId,
1378 "OnuId": onuId,
1379 "SerialNumber": common.OnuSnToString(sn),
1380 "Pkt": omciMsg.Pkt,
1381 }).Fatalf("Failed to send MIB Reset")
1382 }
1383 log.WithFields(log.Fields{
1384 "IntfId": intfId,
1385 "OnuId": onuId,
1386 "SerialNumber": common.OnuSnToString(sn),
1387 "Pkt": omciMsg.Pkt,
1388 }).Tracef("Sent OMCI message %s", msgType)
1389}
1390
1391func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1392 var next uint16
1393 if len(highPriority) > 0 && highPriority[0] {
1394 next = onu.hpTid
1395 onu.hpTid += 1
1396 if onu.hpTid < 0x8000 {
1397 onu.hpTid = 0x8000
1398 }
1399 } else {
1400 next = onu.tid
1401 onu.tid += 1
1402 if onu.tid >= 0x8000 {
1403 onu.tid = 1
1404 }
1405 }
1406 return next
1407}
1408
1409// TODO move this method in responders/omcisim
1410func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1411 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1412 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1413}
1414
Matteo Scandolof9d43412021-01-12 11:11:34 -08001415// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1416func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1417
1418 // we need to encode the packet in HEX
1419 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1420 hex.Encode(pkt, msg.OmciInd.Pkt)
1421 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1422 if err != nil {
1423 log.WithFields(log.Fields{
1424 "IntfId": o.PonPortID,
1425 "SerialNumber": o.Sn(),
1426 "omciPacket": msg.OmciInd.Pkt,
1427 }).Error("BBR Cannot parse OMCI packet")
1428 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001429
1430 log.WithFields(log.Fields{
1431 "IntfId": msg.OmciInd.IntfId,
1432 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001433 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001434 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001435 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301436 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001437 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001438 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001439 log.WithFields(log.Fields{
1440 "IntfId": msg.OmciInd.IntfId,
1441 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001442 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001443 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001444 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001445 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001446 case omci.MibResetResponseType:
1447 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1448 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1449 case omci.MibUploadResponseType:
1450 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1451 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1452 case omci.MibUploadNextResponseType:
1453 o.seqNumber++
1454
1455 if o.seqNumber > 290 {
1456 // 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 -08001457 // 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 -08001458 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001459 onuLogger.WithFields(log.Fields{
1460 "OnuId": o.ID,
1461 "IntfId": o.PonPortID,
1462 "OnuSn": o.Sn(),
1463 }).Errorf("Error while transitioning ONU State %v", err)
1464 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001465 } else {
1466 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1467 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001468 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001469 }
1470}
1471
1472func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1473
1474 classifierProto := openolt.Classifier{
1475 EthType: uint32(layers.EthernetTypeEAPOL),
1476 OVid: 4091,
1477 }
1478
1479 actionProto := openolt.Action{}
1480
1481 downstreamFlow := openolt.Flow{
1482 AccessIntfId: int32(o.PonPortID),
1483 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001484 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001485 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001486 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001487 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001488 Classifier: &classifierProto,
1489 Action: &actionProto,
1490 Priority: int32(100),
1491 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001492 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1493 // AllocId and GemPorts need to be unique per PON
1494 // for now use the ONU-ID, will need to change once we support multiple UNIs
1495 AllocId: int32(o.ID),
1496 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001497 }
1498
1499 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1500 log.WithFields(log.Fields{
1501 "IntfId": o.PonPortID,
1502 "OnuId": o.ID,
1503 "FlowId": downstreamFlow.FlowId,
1504 "PortNo": downstreamFlow.PortNo,
1505 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001506 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001507 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001508 }
1509 log.WithFields(log.Fields{
1510 "IntfId": o.PonPortID,
1511 "OnuId": o.ID,
1512 "FlowId": downstreamFlow.FlowId,
1513 "PortNo": downstreamFlow.PortNo,
1514 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1515 }).Info("Sent EAPOL Flow")
1516}
1517
1518func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001519
1520 // BBR only works with a single service (ATT HSIA)
1521 hsia := o.Services[0].(*Service)
1522
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001523 classifierProto := openolt.Classifier{
1524 EthType: uint32(layers.EthernetTypeIPv4),
1525 SrcPort: uint32(68),
1526 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001527 OVid: uint32(hsia.CTag),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001528 }
1529
1530 actionProto := openolt.Action{}
1531
1532 downstreamFlow := openolt.Flow{
1533 AccessIntfId: int32(o.PonPortID),
1534 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001535 UniId: int32(0), // FIXME do not hardcode this
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001536 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001537 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001538 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001539 Classifier: &classifierProto,
1540 Action: &actionProto,
1541 Priority: int32(100),
1542 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001543 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1544 // AllocId and GemPorts need to be unique per PON
1545 // for now use the ONU-ID, will need to change once we support multiple UNIs
1546 AllocId: int32(o.ID),
1547 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001548 }
1549
1550 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1551 log.WithFields(log.Fields{
1552 "IntfId": o.PonPortID,
1553 "OnuId": o.ID,
1554 "FlowId": downstreamFlow.FlowId,
1555 "PortNo": downstreamFlow.PortNo,
1556 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001557 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001558 }).Fatalf("Failed to send DHCP Flow")
1559 }
1560 log.WithFields(log.Fields{
1561 "IntfId": o.PonPortID,
1562 "OnuId": o.ID,
1563 "FlowId": downstreamFlow.FlowId,
1564 "PortNo": downstreamFlow.PortNo,
1565 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1566 }).Info("Sent DHCP Flow")
1567}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301568
1569// DeleteFlow method search and delete flowKey from the onu flows slice
1570func (onu *Onu) DeleteFlow(key FlowKey) {
1571 for pos, flowKey := range onu.Flows {
1572 if flowKey == key {
1573 // delete the flowKey by shifting all flowKeys by one
1574 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1575 t := make([]FlowKey, len(onu.Flows))
1576 copy(t, onu.Flows)
1577 onu.Flows = t
1578 break
1579 }
1580 }
1581}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301582
1583func (onu *Onu) ReDiscoverOnu() {
1584 // Wait for few seconds to be sure of the cleanup
1585 time.Sleep(5 * time.Second)
1586
1587 onuLogger.WithFields(log.Fields{
1588 "IntfId": onu.PonPortID,
1589 "OnuId": onu.ID,
1590 "OnuSn": onu.Sn(),
1591 }).Debug("Send ONU Re-Discovery")
1592
1593 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001594 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301595 log.WithFields(log.Fields{
1596 "IntfId": onu.PonPortID,
1597 "OnuSn": onu.Sn(),
1598 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001599 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301600 }
1601
Matteo Scandolocedde462021-03-09 17:37:16 -08001602 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301603 log.WithFields(log.Fields{
1604 "IntfId": onu.PonPortID,
1605 "OnuSn": onu.Sn(),
1606 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001607 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301608 }
1609}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001610
1611func (onu *Onu) addGemPortToService(gemport uint32, ethType uint32, oVlan uint32, iVlan uint32) {
1612 for _, s := range onu.Services {
1613 if service, ok := s.(*Service); ok {
1614 // EAPOL is a strange case, as packets are untagged
1615 // but we assume we will have a single service requiring EAPOL
1616 if ethType == uint32(layers.EthernetTypeEAPOL) && service.NeedsEapol {
1617 service.GemPort = gemport
1618 }
1619
1620 // For DHCP services we single tag the outgoing packets,
1621 // thus the flow only contains the CTag and we can use that to match the service
1622 if ethType == uint32(layers.EthernetTypeIPv4) && service.NeedsDhcp && service.CTag == int(oVlan) {
1623 service.GemPort = gemport
1624 }
1625
1626 // for dataplane services match both C and S tags
1627 if service.CTag == int(iVlan) && service.STag == int(oVlan) {
1628 service.GemPort = gemport
1629 }
1630 }
1631 }
1632}
1633
1634func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
1635 for _, s := range onu.Services {
1636 service := s.(*Service)
1637 if service.HwAddress.String() == macAddress.String() {
1638 return service, nil
1639 }
1640 }
1641 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1642}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301643
1644func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1645 switch alarmType {
1646 case "ONU_ALARM_LOS":
1647 msg := bbsim.Message{
1648 Type: bbsim.UniStatusAlarm,
1649 Data: bbsim.UniStatusAlarmMessage{
1650 OnuSN: o.SerialNumber,
1651 OnuID: o.ID,
1652 EntityID: 257,
1653 RaiseOMCIAlarm: raiseOMCIAlarm,
1654 },
1655 }
1656 o.Channel <- msg
1657 }
1658
1659}
1660
1661func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1662 o.onuAlarmsInfoLock.Lock()
1663 defer o.onuAlarmsInfoLock.Unlock()
1664 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1665 if alarmInfo.SequenceNo == 255 {
1666 alarmInfo.SequenceNo = 1
1667 } else {
1668 alarmInfo.SequenceNo++
1669 }
1670 o.onuAlarmsInfo[key] = alarmInfo
1671 return alarmInfo.SequenceNo
1672 } else {
1673 // This is the first time alarm notification message is being sent
1674 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1675 SequenceNo: 1,
1676 }
1677 return 1
1678 }
1679}