blob: 17abfc393e2217e23bb9de0dd7649c15cda6f55d [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"
Mahir Gunyela1753ae2021-06-23 00:24:56 -070023 "sync"
24
Matteo Scandolo8a574812021-05-20 15:18:53 -070025 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
26 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
27 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000028
Matteo Scandolof9d43412021-01-12 11:11:34 -080029 pb "github.com/opencord/bbsim/api/bbsim"
30 "github.com/opencord/bbsim/internal/bbsim/alarmsim"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000031
32 "net"
33 "strconv"
34 "time"
Himani Chawla13b1ee02021-03-15 01:43:53 +053035
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080036 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
37 me "github.com/opencord/omci-lib-go/generated"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010038
Matteo Scandolo3bc73742019-08-20 14:04:04 -070039 "github.com/google/gopacket/layers"
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070040 "github.com/jpillora/backoff"
Matteo Scandolo4747d292019-08-05 11:50:18 -070041 "github.com/looplab/fsm"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070042 "github.com/opencord/bbsim/internal/common"
43 omcilib "github.com/opencord/bbsim/internal/common/omci"
Matteo Scandolof9d43412021-01-12 11:11:34 -080044 "github.com/opencord/omci-lib-go"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070045 "github.com/opencord/voltha-protos/v4/go/openolt"
46 "github.com/opencord/voltha-protos/v4/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070047 log "github.com/sirupsen/logrus"
48)
49
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070050var onuLogger = log.WithFields(log.Fields{
51 "module": "ONU",
52})
53
Matteo Scandolocedde462021-03-09 17:37:16 -080054const (
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000055 maxOmciMsgCounter = 10
56)
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
Matteo Scandolo4a036262020-08-17 15:56:13 -0700106 Backoff *backoff.Backoff
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800107 // ONU State
Matteo Scandolo8a574812021-05-20 15:18:53 -0700108 UniPorts []UniPortIf
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700109 Flows []FlowKey
110 FlowIds []uint64 // keep track of the flows we currently have in the ONU
Matteo Scandolo99f18462019-10-28 14:14:28 -0700111
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700112 OperState *fsm.FSM
113 SerialNumber *openolt.SerialNumber
114
Matteo Scandolof9d43412021-01-12 11:11:34 -0800115 Channel chan bbsim.Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700116
117 // OMCI params
Matteo Scandolocedde462021-03-09 17:37:16 -0800118 MibDataSync uint8
119 ImageSoftwareExpectedSections int
120 ImageSoftwareReceivedSections int
121 ActiveImageEntityId uint16
122 CommittedImageEntityId uint16
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700123 StandbyImageVersion string
124 ActiveImageVersion string
125 CommittedImageVersion string
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000126 OmciResponseRate uint8
127 OmciMsgCounter uint8
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800128
129 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700130 tid uint16
131 hpTid uint16
132 seqNumber uint16
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700133 MibDb *omcilib.MibDb
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 Scandolo8a574812021-05-20 15:18:53 -0700145func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, nextCtag map[string]int, nextStag map[string]int, 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,
Matteo Scandolocedde462021-03-09 17:37:16 -0800151 tid: 0x1,
152 hpTid: 0x8000,
153 seqNumber: 0,
154 DoneChannel: make(chan bool, 1),
155 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
156 Flows: []FlowKey{},
157 DiscoveryDelay: delay,
158 MibDataSync: 0,
159 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
160 ImageSoftwareReceivedSections: 0,
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700161 //TODO this needs reworking, it's always 0 or 1, possibly base all on the version
162 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
163 CommittedImageEntityId: 0,
164 StandbyImageVersion: "BBSM_IMG_00000",
165 ActiveImageVersion: "BBSM_IMG_00001",
166 CommittedImageVersion: "BBSM_IMG_00001",
167 OmciResponseRate: olt.OmciResponseRate,
168 OmciMsgCounter: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700169 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800170 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700171 // NOTE this state machine is used to track the operational
172 // state as requested by VOLTHA
173 o.OperState = getOperStateFSM(func(e *fsm.Event) {
174 onuLogger.WithFields(log.Fields{
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700175 "OnuId": o.ID,
176 "IntfId": o.PonPortID,
177 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700178 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
179 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530180 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700181 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
182 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800183 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700184 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700185 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800186 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
187 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
188 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100189 // 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 -0800190 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530191 // ONU state when PON port is disabled but ONU is power ON(more states should be added in src?)
Matteo Scandolo9f4bf4f2021-06-22 09:41:02 +0200192 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted, OnuStateImageDownloadComplete}, Dst: OnuStatePonDisabled},
Matteo Scandolocedde462021-03-09 17:37:16 -0800193 // Software Image Download related states
Matteo Scandolo9f4bf4f2021-06-22 09:41:02 +0200194 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateImageDownloadStarted},
Matteo Scandolocedde462021-03-09 17:37:16 -0800195 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
196 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
197 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
198 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
199 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700200 // BBR States
201 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800202 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
203 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700204 },
205 fsm.Callbacks{
206 "enter_state": func(e *fsm.Event) {
207 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700208 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700209 fmt.Sprintf("enter_%s", OnuStateInitialized): func(e *fsm.Event) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100210 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800211 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800212
Matteo Scandolocedde462021-03-09 17:37:16 -0800213 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800214 onuLogger.WithFields(log.Fields{
215 "OnuId": o.ID,
216 "IntfId": o.PonPortID,
217 "OnuSn": o.Sn(),
218 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
219 }
220
Pragya Arya1cbefa42020-01-13 12:15:29 +0530221 if !isMock {
222 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700223 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530224 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100225 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700226 fmt.Sprintf("enter_%s", OnuStateDiscovered): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800227 msg := bbsim.Message{
228 Type: bbsim.OnuDiscIndication,
229 Data: bbsim.OnuDiscIndicationMessage{
230 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100231 },
232 }
233 o.Channel <- msg
234 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700235 fmt.Sprintf("enter_%s", OnuStateEnabled): func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800236
237 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
238 onuLogger.WithFields(log.Fields{
239 "IntfId": o.PonPortID,
240 "OnuId": o.ID,
241 "SerialNumber": o.Sn(),
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700242 }).Errorf("onu-id-duplicated-with-%s", common.OnuSnToString(sn))
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800243 return
244 } else {
245 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
246 }
247
Matteo Scandolof9d43412021-01-12 11:11:34 -0800248 msg := bbsim.Message{
249 Type: bbsim.OnuIndication,
250 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700251 OnuSN: o.SerialNumber,
252 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800253 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700254 },
255 }
256 o.Channel <- msg
257 },
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
Matteo Scandolo8a574812021-05-20 15:18:53 -0700281 // disable the UNI ports
282 for _, uni := range o.UniPorts {
283 _ = uni.Disable()
284 }
285
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530286 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100287 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolo8a574812021-05-20 15:18:53 -0700288 // NOTE may need to wait for the UNIs to be down too before shutting down the channel
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530289 if len(o.FlowIds) == 0 {
290 close(o.Channel)
291 }
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700292 },
293 fmt.Sprintf("enter_%s", OnuStatePonDisabled): func(event *fsm.Event) {
294 o.cleanupOnuState()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700295 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700296 // BBR states
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700297 fmt.Sprintf("enter_%s", BbrOnuStateEapolFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800298 msg := bbsim.Message{
299 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700300 }
301 o.Channel <- msg
302 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700303 fmt.Sprintf("enter_%s", BbrOnuStateDhcpFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800304 msg := bbsim.Message{
305 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700306 }
307 o.Channel <- msg
308 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700309 },
310 )
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700311 onuLogger.WithFields(log.Fields{
312 "OnuId": o.ID,
313 "IntfId": o.PonPortID,
314 "OnuSn": o.Sn(),
315 "NumUni": olt.NumUni,
316 }).Debug("creating-uni-ports")
317 for i := 0; i < olt.NumUni; i++ {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700318 uni, err := NewUniPort(uint32(i), &o, nextCtag, nextStag)
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700319 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
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700354 o.Flows = []FlowKey{}
355 o.PonPort.removeOnuId(o.ID)
356 o.PonPort.removeAllocId(o.SerialNumber)
357 o.PonPort.removeGemPortBySn(o.SerialNumber)
358
359 o.onuAlarmsInfoLock.Lock()
360 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
361 o.onuAlarmsInfoLock.Unlock()
362}
363
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100364// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000365func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700366 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100367 "onuID": o.ID,
368 "onuSN": o.Sn(),
369 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700370 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100371 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700372
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700373 defer onuLogger.WithFields(log.Fields{
374 "onuID": o.ID,
375 "onuSN": o.Sn(),
376 "stream": stream,
377 }).Debug("Stopped handling ONU Indication Channel")
378
David Bainbridge103cf022019-12-16 20:11:35 +0000379loop:
380 for {
381 select {
382 case <-ctx.Done():
383 onuLogger.WithFields(log.Fields{
384 "onuID": o.ID,
385 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700386 }).Debug("ONU message handling canceled via context")
387 break loop
388 case <-stream.Context().Done():
389 onuLogger.WithFields(log.Fields{
390 "onuID": o.ID,
391 "onuSN": o.Sn(),
392 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000393 break loop
394 case message, ok := <-o.Channel:
395 if !ok || ctx.Err() != nil {
396 onuLogger.WithFields(log.Fields{
397 "onuID": o.ID,
398 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700399 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000400 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700401 }
David Bainbridge103cf022019-12-16 20:11:35 +0000402 onuLogger.WithFields(log.Fields{
403 "onuID": o.ID,
404 "onuSN": o.Sn(),
405 "messageType": message.Type,
406 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700407
David Bainbridge103cf022019-12-16 20:11:35 +0000408 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800409 case bbsim.OnuDiscIndication:
410 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000411 // 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 +0530412 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000413 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800414 case bbsim.OnuIndication:
415 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000416 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800417 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800418 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800419 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200420 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800421 case bbsim.UniStatusAlarm:
422 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530423 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
424 MeInstance: msg.EntityID,
425 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
426 }
427 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
428 o.onuAlarmsInfoLock.Lock()
429 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
430 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
431 if pkt != nil { //pkt will be nil if we are unable to create the alarm
432 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
433 onuLogger.WithFields(log.Fields{
434 "IntfId": o.PonPortID,
435 "SerialNumber": o.Sn(),
436 "omciPacket": pkt,
437 "adminState": msg.AdminState,
438 "entityID": msg.EntityID,
439 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
440 alarmInfo.SequenceNo--
441 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800442 onuLogger.WithFields(log.Fields{
443 "IntfId": o.PonPortID,
444 "SerialNumber": o.Sn(),
445 "omciPacket": pkt,
446 "adminState": msg.AdminState,
447 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530448 }).Trace("UNI-Link-alarm-sent")
449 if alarmBitMap == [28]byte{0} {
450 delete(o.onuAlarmsInfo, onuAlarmMapKey)
451 } else {
452 alarmInfo.AlarmBitMap = alarmBitMap
453 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
454 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800455 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530456 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800457 case bbsim.FlowAdd:
458 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700459 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800460 case bbsim.FlowRemoved:
461 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700462 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800463 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700464
Matteo Scandolof9d43412021-01-12 11:11:34 -0800465 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000466
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700467 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000468 "IntfId": msg.IntfId,
469 "OnuId": msg.OnuId,
470 "pktType": msg.Type,
471 }).Trace("Received OnuPacketOut Message")
472
Matteo Scandolo8a574812021-05-20 15:18:53 -0700473 uni, err := o.findUniByPortNo(msg.PortNo)
Matteo Scandolo618a6582020-09-09 12:21:29 -0700474
Matteo Scandolo8a574812021-05-20 15:18:53 -0700475 if err != nil {
476 onuLogger.WithFields(log.Fields{
477 "IntfId": msg.IntfId,
478 "OnuId": msg.OnuId,
479 "pktType": msg.Type,
480 "portNo": msg.PortNo,
481 "MacAddress": msg.MacAddress,
482 "Pkt": hex.EncodeToString(msg.Packet.Data()),
483 "OnuSn": o.Sn(),
484 }).Error("Cannot find Uni associated with packet")
485 return
David Bainbridge103cf022019-12-16 20:11:35 +0000486 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700487 uni.PacketCh <- msg
488 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800489 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000490 // NOTE we only receive BBR packets here.
491 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
492 // 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 -0800493 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000494
Matteo Scandolo8a574812021-05-20 15:18:53 -0700495 onuLogger.WithFields(log.Fields{
496 "IntfId": msg.IntfId,
497 "OnuId": msg.OnuId,
498 "PortNo": msg.PortNo,
499 "GemPortId": msg.GemPortId,
500 "pktType": msg.Type,
David Bainbridge103cf022019-12-16 20:11:35 +0000501 }).Trace("Received OnuPacketIn Message")
502
Matteo Scandolo8a574812021-05-20 15:18:53 -0700503 uni, err := o.findUniByPortNo(msg.PortNo)
504 if err != nil {
505 onuLogger.WithFields(log.Fields{
506 "IntfId": msg.IntfId,
507 "OnuId": msg.OnuId,
508 "PortNo": msg.PortNo,
509 "GemPortId": msg.GemPortId,
510 "pktType": msg.Type,
511 }).Error(err.Error())
512 }
513
514 // BBR has one service and one UNI
515 serviceId := uint32(0)
516 oltId := 0
David Bainbridge103cf022019-12-16 20:11:35 +0000517 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700518 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, msg.GemPortId, o.Sn(), msg.PortNo, uni.ID, serviceId, oltId, o.InternalState, msg.Packet, stream, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000519 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700520 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000521 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800522 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800523 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800524 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
525 o.handleOmciResponse(msg, client)
526 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000527 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800528 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000529 o.sendDhcpFlow(client)
530 default:
531 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700532 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700533 }
534 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700535}
536
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800537func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700538 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700539 sn.VendorId = []byte("BBSM")
540 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700541 return sn
542}
543
Matteo Scandolof9d43412021-01-12 11:11:34 -0800544func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700545 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800546 IntfId: o.PonPortID,
547 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700548 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700549
Matteo Scandolo4747d292019-08-05 11:50:18 -0700550 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700551 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700552 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700553 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700554
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700555 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800556 "IntfId": o.PonPortID,
557 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700558 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700559 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800560 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800561
562 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
563 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800564 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800565 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800566 o.sendOnuDiscIndication(msg, stream)
567 }
568 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700569}
570
Matteo Scandolof9d43412021-01-12 11:11:34 -0800571func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800572 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
573 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700574
575 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700576 IntfId: o.PonPortID,
577 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700578 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700579 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700580 SerialNumber: o.SerialNumber,
581 }}
582 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800583 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700584 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700585 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700586 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700587 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800588 "IntfId": o.PonPortID,
589 "OnuId": o.ID,
590 "VolthaOnuId": msg.OnuID,
591 "OperState": msg.OperState.String(),
592 "AdminState": msg.OperState.String(),
593 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700594 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700595
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700596}
597
Matteo Scandolof9d43412021-01-12 11:11:34 -0800598func (o *Onu) HandleShutdownONU() error {
599
600 dyingGasp := pb.ONUAlarmRequest{
601 AlarmType: "DYING_GASP",
602 SerialNumber: o.Sn(),
603 Status: "on",
604 }
605
606 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
607 onuLogger.WithFields(log.Fields{
608 "OnuId": o.ID,
609 "IntfId": o.PonPortID,
610 "OnuSn": o.Sn(),
611 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
612 return err
613 }
614
615 losReq := pb.ONUAlarmRequest{
616 AlarmType: "ONU_ALARM_LOS",
617 SerialNumber: o.Sn(),
618 Status: "on",
619 }
620
621 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
622 onuLogger.WithFields(log.Fields{
623 "OnuId": o.ID,
624 "IntfId": o.PonPortID,
625 "OnuSn": o.Sn(),
626 }).Errorf("Cannot send LOS: %s", err.Error())
627
628 return err
629 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530630 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800631 // TODO if it's the last ONU on the PON, then send a PON LOS
632
Matteo Scandolocedde462021-03-09 17:37:16 -0800633 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800634 onuLogger.WithFields(log.Fields{
635 "OnuId": o.ID,
636 "IntfId": o.PonPortID,
637 "OnuSn": o.Sn(),
638 }).Errorf("Cannot shutdown ONU: %s", err.Error())
639 return err
640 }
641
642 return nil
643}
644
645func (o *Onu) HandlePowerOnONU() error {
646 intitalState := o.InternalState.Current()
647
648 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800649 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
650 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800651 onuLogger.WithFields(log.Fields{
652 "OnuId": o.ID,
653 "IntfId": o.PonPortID,
654 "OnuSn": o.Sn(),
655 }).Errorf("Cannot poweron ONU: %s", err.Error())
656 return err
657 }
658 }
659
660 // turn off the LOS Alarm
661 losReq := pb.ONUAlarmRequest{
662 AlarmType: "ONU_ALARM_LOS",
663 SerialNumber: o.Sn(),
664 Status: "off",
665 }
666
667 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
668 onuLogger.WithFields(log.Fields{
669 "OnuId": o.ID,
670 "IntfId": o.PonPortID,
671 "OnuSn": o.Sn(),
672 }).Errorf("Cannot send LOS: %s", err.Error())
673 return err
674 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530675 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800676
677 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800678 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800679 onuLogger.WithFields(log.Fields{
680 "OnuId": o.ID,
681 "IntfId": o.PonPortID,
682 "OnuSn": o.Sn(),
683 }).Errorf("Cannot poweron ONU: %s", err.Error())
684 return err
685 }
686
687 // move o directly to enable state only when its a powercycle case
688 // in case of first time o poweron o will be moved to enable on
689 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800690 if intitalState == OnuStateDisabled {
691 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800692 onuLogger.WithFields(log.Fields{
693 "OnuId": o.ID,
694 "IntfId": o.PonPortID,
695 "OnuSn": o.Sn(),
696 }).Errorf("Cannot enable ONU: %s", err.Error())
697 return err
698 }
699 }
700
701 return nil
702}
703
704func (o *Onu) SetAlarm(alarmType string, status string) error {
705 alarmReq := pb.ONUAlarmRequest{
706 AlarmType: alarmType,
707 SerialNumber: o.Sn(),
708 Status: status,
709 }
710
711 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
712 if err != nil {
713 return err
714 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530715 raiseAlarm := false
716 if alarmReq.Status == "on" {
717 raiseAlarm = true
718 }
719 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800720 return nil
721}
722
723func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530724 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700725 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530726 if err != nil {
727 log.Errorf("error in getting msgType %v", err)
728 return
729 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800730 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530731 o.seqNumber = 0
732 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800733 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530734 o.seqNumber++
735 if o.seqNumber > 290 {
736 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
737 }
738 }
739 }
740}
741
Matteo Scandolof9d43412021-01-12 11:11:34 -0800742// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
743// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200744func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800745
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700746 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700747 "omciMsgType": msg.OmciMsg.MessageType,
748 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
749 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700750 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700751 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800752 }).Trace("omci-message-decoded")
753
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000754 if o.OmciMsgCounter < maxOmciMsgCounter {
755 o.OmciMsgCounter++
756 } else {
757 o.OmciMsgCounter = 1
758 }
759 if o.OmciMsgCounter > o.OmciResponseRate {
760 onuLogger.WithFields(log.Fields{
761 "OmciMsgCounter": o.OmciMsgCounter,
762 "OmciResponseRate": o.OmciResponseRate,
763 "omciMsgType": msg.OmciMsg.MessageType,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200764 }).Debug("skipping-omci-msg-response")
765 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000766 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800767 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800768 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700769 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800770 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800771 onuLogger.WithFields(log.Fields{
772 "IntfId": o.PonPortID,
773 "OnuId": o.ID,
774 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700775 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700776 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800777 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700778
779 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
780 o.PonPort.removeAllocId(o.SerialNumber)
781 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800782 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800783 case omci.MibUploadRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700784 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800785 case omci.MibUploadNextRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700786 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800787 case omci.GetRequestType:
Girish Gowdra996d81e2021-04-21 16:16:27 -0700788 onuDown := o.OperState.Current() == "down"
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700789 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId,
790 o.CommittedImageEntityId, o.StandbyImageVersion, o.ActiveImageVersion, o.CommittedImageVersion, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800791 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800792 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700793 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800794 switch msgObj.EntityClass {
795 case me.PhysicalPathTerminationPointEthernetUniClassID:
796 // if we're Setting a PPTP state
Matteo Scandolo8a574812021-05-20 15:18:53 -0700797 // we need to send the appropriate alarm (handled in the UNI struct)
798 uni, err := o.FindUniByEntityId(msgObj.EntityInstance)
799 if err != nil {
800 onuLogger.Error(err)
801 success = false
802 } else {
803 // 1 locks the UNI, 0 unlocks it
Matteo Scandolof9d43412021-01-12 11:11:34 -0800804 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Matteo Scandolo8a574812021-05-20 15:18:53 -0700805 var err error
Himani Chawla13b1ee02021-03-15 01:43:53 +0530806 if adminState == 1 {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700807 err = uni.Disable()
Girish Gowdra996d81e2021-04-21 16:16:27 -0700808 } else {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700809 err = uni.Enable()
Himani Chawla13b1ee02021-03-15 01:43:53 +0530810 }
Matteo Scandolo8a574812021-05-20 15:18:53 -0700811 if err != nil {
812 onuLogger.WithFields(log.Fields{
813 "IntfId": o.PonPortID,
814 "OnuId": o.ID,
815 "UniMeId": uni.MeId,
816 "UniId": uni.ID,
817 "SerialNumber": o.Sn(),
818 "Err": err.Error(),
819 }).Warn("cannot-change-uni-status")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800820 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800821 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800822 case me.TContClassID:
823 allocId := msgObj.Attributes["AllocId"].(uint16)
824
825 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
826 // otherwise we are adding it
827 if allocId == 255 || allocId == 65535 {
828 onuLogger.WithFields(log.Fields{
829 "IntfId": o.PonPortID,
830 "OnuId": o.ID,
831 "TContId": msgObj.EntityInstance,
832 "AllocId": allocId,
833 "SerialNumber": o.Sn(),
834 }).Trace("freeing-alloc-id-via-omci")
835 o.PonPort.removeAllocId(o.SerialNumber)
836 } else {
837 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
838 onuLogger.WithFields(log.Fields{
839 "IntfId": o.PonPortID,
840 "OnuId": o.ID,
841 "AllocId": allocId,
842 "SerialNumber": o.Sn(),
843 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
844 success = false
845 } else {
846 onuLogger.WithFields(log.Fields{
847 "IntfId": o.PonPortID,
848 "OnuId": o.ID,
849 "TContId": msgObj.EntityInstance,
850 "AllocId": allocId,
851 "SerialNumber": o.Sn(),
852 }).Trace("storing-alloc-id-via-omci")
853 o.PonPort.storeAllocId(allocId, o.SerialNumber)
854 }
855 }
856
857 }
858
859 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700860 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800861 o.MibDataSync++
862 }
863 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700864 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800865 }
866 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800867 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
868 var used bool
869 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700870 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800871 if err == nil {
872 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700873 // GemPort 4069 is reserved for multicast and shared across ONUs
874 if msgObj.EntityInstance != 4069 {
875 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
876 onuLogger.WithFields(log.Fields{
877 "IntfId": o.PonPortID,
878 "OnuId": o.ID,
879 "GemPortId": msgObj.EntityInstance,
880 "SerialNumber": o.Sn(),
881 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
882 } else {
883 onuLogger.WithFields(log.Fields{
884 "IntfId": o.PonPortID,
885 "OnuId": o.ID,
886 "GemPortId": msgObj.EntityInstance,
887 "SerialNumber": o.Sn(),
888 }).Trace("storing-gem-port-id-via-omci")
889 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
890 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800891 }
892 }
893 }
894
895 // if the gemPort is valid then increment the MDS and return a successful response
896 // otherwise fail the request
897 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
898 // validation this check will need to be rewritten
899 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700900 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800901 o.MibDataSync++
902 }
903 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700904 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800905 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800906 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700907 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800908 if err == nil {
909 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
910 onuLogger.WithFields(log.Fields{
911 "IntfId": o.PonPortID,
912 "OnuId": o.ID,
913 "GemPortId": msgObj.EntityInstance,
914 "SerialNumber": o.Sn(),
915 }).Trace("freeing-gem-port-id-via-omci")
916 o.PonPort.removeGemPort(msgObj.EntityInstance)
917 }
918 }
919
Matteo Scandolob5913142021-03-19 16:10:18 -0700920 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800921 o.MibDataSync++
922 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800923 case omci.RebootRequestType:
924
Matteo Scandolob5913142021-03-19 16:10:18 -0700925 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800926
927 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800928 // we run this in a separate goroutine so that
929 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800930 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800931 if err := o.Reboot(10 * time.Second); err != nil {
932 log.WithFields(log.Fields{
933 "IntfId": o.PonPortID,
934 "OnuId": o.ID,
935 "SerialNumber": o.Sn(),
936 "err": err,
937 }).Error("cannot-reboot-onu-after-omci-reboot-request")
938 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800939 }()
940 case omci.TestRequestType:
Girish Gowdra161d27a2021-05-05 12:01:44 -0700941 var classID me.ClassID
942 var omciResult me.Results
943 var instID uint16
944 responsePkt, errResp, classID, instID, omciResult = omcilib.CreateTestResponse(msg.OmciPkt, msg.OmciMsg)
945 // Send TestResult only in case the TestResponse omci result code is me.Success
946 if responsePkt != nil && errResp == nil && omciResult == me.Success {
947 if testResultPkt, err := omcilib.CreateTestResult(classID, instID, msg.OmciMsg.TransactionID); err == nil {
948 // send test results asynchronously
949 go func() {
950 // Send test results after a second to emulate async behavior
951 time.Sleep(1 * time.Second)
952 if testResultPkt != nil {
953 if err := o.sendOmciIndication(testResultPkt, msg.OmciMsg.TransactionID, stream); err != nil {
954 onuLogger.WithFields(log.Fields{
955 "IntfId": o.PonPortID,
956 "SerialNumber": o.Sn(),
957 "omciPacket": testResultPkt,
958 "msg.OmciMsgType": msg.OmciMsg.MessageType,
959 "transCorrId": msg.OmciMsg.TransactionID,
960 }).Errorf("failed-to-send-omci-message: %v", err)
961 }
962 }
963 }()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800964 }
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")
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001003 //Extracting the first 14 bytes to use as a version for this image.
1004 if o.ImageSoftwareReceivedSections == 0 {
1005 o.StandbyImageVersion = string(msgObj.SectionData[0:14])
1006 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001007 o.ImageSoftwareReceivedSections++
1008 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1009 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1010 onuLogger.WithFields(log.Fields{
1011 "OnuId": o.ID,
1012 "IntfId": o.PonPortID,
1013 "OnuSn": o.Sn(),
1014 "Err": err.Error(),
1015 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1016 }
1017 }
1018 }
1019 case omci.DownloadSectionRequestWithResponseType:
1020 // NOTE we only need to respond if an ACK is requested
Matteo Scandolob5913142021-03-19 16:10:18 -07001021 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1022 if errResp != nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001023 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001024 "OmciMsgType": msg.OmciMsg.MessageType,
1025 "TransCorrId": msg.OmciMsg.TransactionID,
1026 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001027 "IntfId": o.PonPortID,
1028 "SerialNumber": o.Sn(),
1029 }).Error("error-while-processing-create-download-section-response")
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001030 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
Matteo Scandolocedde462021-03-09 17:37:16 -08001031 }
1032 o.ImageSoftwareReceivedSections++
Matteo Scandolocedde462021-03-09 17:37:16 -08001033 case omci.EndSoftwareDownloadRequestType:
1034
1035 // In the startSoftwareDownload we get the image size and the window size.
1036 // We calculate how many DownloadSection we should receive and validate
1037 // that we got the correct amount when we receive this message
1038 success := true
1039 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1040 onuLogger.WithFields(log.Fields{
1041 "OnuId": o.ID,
1042 "IntfId": o.PonPortID,
1043 "OnuSn": o.Sn(),
1044 "ExpectedSections": o.ImageSoftwareExpectedSections,
1045 "ReceivedSections": o.ImageSoftwareReceivedSections,
1046 }).Errorf("onu-did-not-receive-all-image-sections")
1047 success = false
1048 }
1049
1050 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001051 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001052 o.MibDataSync++
1053 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1054 onuLogger.WithFields(log.Fields{
1055 "OnuId": o.ID,
1056 "IntfId": o.PonPortID,
1057 "OnuSn": o.Sn(),
1058 "Err": err.Error(),
1059 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1060 }
1061 } else {
1062 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001063 "OmciMsgType": msg.OmciMsg.MessageType,
1064 "TransCorrId": msg.OmciMsg.TransactionID,
1065 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001066 "IntfId": o.PonPortID,
1067 "SerialNumber": o.Sn(),
1068 }).Error("error-while-processing-end-software-download-request")
1069 }
1070 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001071 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001072 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1073 onuLogger.WithFields(log.Fields{
1074 "OnuId": o.ID,
1075 "IntfId": o.PonPortID,
1076 "OnuSn": o.Sn(),
1077 "Err": err.Error(),
1078 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1079 }
1080 }
1081 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001082 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001083 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001084 o.MibDataSync++
1085 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1086 onuLogger.WithFields(log.Fields{
1087 "OnuId": o.ID,
1088 "IntfId": o.PonPortID,
1089 "OnuSn": o.Sn(),
1090 "Err": err.Error(),
1091 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1092 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001093 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001094 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001095 previousActiveImage := o.ActiveImageVersion
1096 o.ActiveImageVersion = o.StandbyImageVersion
1097 o.StandbyImageVersion = previousActiveImage
Matteo Scandolocedde462021-03-09 17:37:16 -08001098 } else {
1099 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1100 }
1101 onuLogger.WithFields(log.Fields{
1102 "OnuId": o.ID,
1103 "IntfId": o.PonPortID,
1104 "OnuSn": o.Sn(),
1105 "ActiveImageEntityId": o.ActiveImageEntityId,
1106 "CommittedImageEntityId": o.CommittedImageEntityId,
1107 }).Info("onu-software-image-activated")
1108
1109 // powercycle the ONU
1110 // we run this in a separate goroutine so that
1111 // the ActivateSoftwareResponse is sent to VOLTHA
1112 // NOTE do we need to wait before rebooting?
1113 go func() {
1114 if err := o.Reboot(10 * time.Second); err != nil {
1115 log.WithFields(log.Fields{
1116 "IntfId": o.PonPortID,
1117 "OnuId": o.ID,
1118 "SerialNumber": o.Sn(),
1119 "err": err,
1120 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1121 }
1122 }()
1123 }
1124 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001125 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001126 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001127 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001128 // TODO validate that the image to commit is:
1129 // - active
1130 // - not already committed
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001131 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandolocedde462021-03-09 17:37:16 -08001132 o.CommittedImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001133 //committed becomes standby
1134 o.StandbyImageVersion = o.CommittedImageVersion
1135 o.CommittedImageVersion = o.ActiveImageVersion
Matteo Scandolocedde462021-03-09 17:37:16 -08001136 } else {
1137 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1138 }
1139 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1140 onuLogger.WithFields(log.Fields{
1141 "OnuId": o.ID,
1142 "IntfId": o.PonPortID,
1143 "OnuSn": o.Sn(),
1144 "Err": err.Error(),
1145 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1146 }
1147 onuLogger.WithFields(log.Fields{
1148 "OnuId": o.ID,
1149 "IntfId": o.PonPortID,
1150 "OnuSn": o.Sn(),
1151 "ActiveImageEntityId": o.ActiveImageEntityId,
1152 "CommittedImageEntityId": o.CommittedImageEntityId,
1153 }).Info("onu-software-image-committed")
1154 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301155 case omci.GetAllAlarmsRequestType:
1156 // Reset the alarm sequence number on receiving get all alarms request.
1157 o.onuAlarmsInfoLock.Lock()
1158 for key, alarmInfo := range o.onuAlarmsInfo {
1159 // reset the alarm sequence no
1160 alarmInfo.SequenceNo = 0
1161 o.onuAlarmsInfo[key] = alarmInfo
1162 }
1163 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001164 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301165 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001166 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301167 responsePkt = nil //Do not send any response for error case
1168 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001169 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001170 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001171 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1172 "omciPkt": msg.OmciPkt,
1173 "omciMsgType": msg.OmciMsg.MessageType,
1174 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001175 "IntfId": o.PonPortID,
1176 "SerialNumber": o.Sn(),
1177 }).Warnf("OMCI-message-not-supported")
1178 }
1179
1180 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001181 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001182 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001183 "IntfId": o.PonPortID,
1184 "SerialNumber": o.Sn(),
1185 "omciPacket": responsePkt,
1186 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1187 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001188 }).Errorf("failed-to-send-omci-message: %v", err)
1189 }
1190 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001191
Pragya Arya324337e2020-02-20 14:35:08 +05301192 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001193 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001194}
Pragya Arya324337e2020-02-20 14:35:08 +05301195
Matteo Scandolof9d43412021-01-12 11:11:34 -08001196// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1197func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1198 indication := &openolt.Indication_OmciInd{
1199 OmciInd: &openolt.OmciIndication{
1200 IntfId: o.PonPortID,
1201 OnuId: o.ID,
1202 Pkt: responsePkt,
1203 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001204 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001205 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1206 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001207 }
1208 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001209 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001210 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001211 "omciPacket": indication.OmciInd.Pkt,
1212 "transCorrId": txId,
1213 }).Trace("omci-message-sent")
1214 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001215}
1216
Matteo Scandolo8a574812021-05-20 15:18:53 -07001217// FindUniById retrieves a UNI by ID
1218func (o *Onu) FindUniById(uniID uint32) (*UniPort, error) {
1219 for _, u := range o.UniPorts {
1220 uni := u.(*UniPort)
1221 if uni.ID == uniID {
1222 return uni, nil
1223 }
Matteo Scandolo27428702019-10-11 16:21:16 -07001224 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001225 return nil, fmt.Errorf("cannot-find-uni-with-id-%d-on-onu-%s", uniID, o.Sn())
1226}
1227
1228// FindUniByEntityId retrieves a uni by MeID (the OMCI entity ID)
1229func (o *Onu) FindUniByEntityId(meId uint16) (*UniPort, error) {
1230 entityId := omcilib.EntityID{}.FromUint16(meId)
1231 for _, u := range o.UniPorts {
1232 uni := u.(*UniPort)
1233 if uni.MeId.Equals(entityId) {
1234 return uni, nil
1235 }
1236 }
1237 return nil, fmt.Errorf("cannot-find-uni-with-meid-%s-on-onu-%s", entityId.ToString(), o.Sn())
Matteo Scandolo27428702019-10-11 16:21:16 -07001238}
1239
William Kurkian0418bc82019-11-06 12:16:24 -05001240func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001241 onuLogger.WithFields(log.Fields{
1242 "IntfId": o.PonPortID,
1243 "OnuId": id,
1244 "SerialNumber": o.Sn(),
1245 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001246 o.ID = id
1247}
1248
Matteo Scandolof9d43412021-01-12 11:11:34 -08001249func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001250 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001251 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001252 "Cookie": msg.Flow.Cookie,
1253 "DstPort": msg.Flow.Classifier.DstPort,
1254 "FlowId": msg.Flow.FlowId,
1255 "FlowType": msg.Flow.FlowType,
1256 "GemportId": msg.Flow.GemportId,
1257 "InnerVlan": msg.Flow.Classifier.IVid,
1258 "IntfId": msg.Flow.AccessIntfId,
1259 "IpProto": msg.Flow.Classifier.IpProto,
1260 "OnuId": msg.Flow.OnuId,
1261 "OnuSn": o.Sn(),
1262 "OuterVlan": msg.Flow.Classifier.OVid,
1263 "PortNo": msg.Flow.PortNo,
1264 "SrcPort": msg.Flow.Classifier.SrcPort,
1265 "UniID": msg.Flow.UniId,
1266 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1267 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1268 "ClassifierIVid": msg.Flow.Classifier.IVid,
1269 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001270 "ReplicateFlow": msg.Flow.ReplicateFlow,
1271 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001272 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001273
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001274 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001275
1276 var gemPortId uint32
1277 if msg.Flow.ReplicateFlow {
1278 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1279 // first available gemport (we only need to send one packet)
1280 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1281 gemPortId = msg.Flow.PbitToGemport[0]
1282 } else {
1283 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1284 gemPortId = uint32(msg.Flow.GemportId)
1285 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001286
1287 uni, err := o.FindUniById(uint32(msg.Flow.UniId))
1288 if err != nil {
1289 onuLogger.WithFields(log.Fields{
1290 "IntfId": o.PonPortID,
1291 "OnuId": o.ID,
1292 "UniId": msg.Flow.UniId,
1293 "PortNo": msg.Flow.PortNo,
1294 "SerialNumber": o.Sn(),
1295 "FlowId": msg.Flow.FlowId,
1296 "FlowType": msg.Flow.FlowType,
1297 }).Error("cannot-find-uni-port-for-flow")
1298 }
1299
1300 uni.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
1301 uni.StorePortNo(msg.Flow.PortNo)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001302
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001303 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001304 uni.HandleAuth()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001305 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1306 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001307 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001308 uni.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001309 }
1310}
1311
Matteo Scandolof9d43412021-01-12 11:11:34 -08001312func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001313 onuLogger.WithFields(log.Fields{
1314 "IntfId": o.PonPortID,
1315 "OnuId": o.ID,
1316 "SerialNumber": o.Sn(),
1317 "FlowId": msg.Flow.FlowId,
1318 "FlowType": msg.Flow.FlowType,
1319 }).Debug("ONU receives FlowRemove")
1320
1321 for idx, flow := range o.FlowIds {
1322 // If the gemport is found, delete it from local cache.
1323 if flow == msg.Flow.FlowId {
1324 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1325 break
1326 }
1327 }
1328
1329 if len(o.FlowIds) == 0 {
1330 onuLogger.WithFields(log.Fields{
1331 "IntfId": o.PonPortID,
1332 "OnuId": o.ID,
1333 "SerialNumber": o.Sn(),
1334 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001335
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301336 // check if ONU delete is performed and
1337 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001338 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301339 close(o.Channel)
1340 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001341 }
1342}
1343
Matteo Scandolocedde462021-03-09 17:37:16 -08001344func (o *Onu) Reboot(timeout time.Duration) error {
1345 onuLogger.WithFields(log.Fields{
1346 "IntfId": o.PonPortID,
1347 "OnuId": o.ID,
1348 "SerialNumber": o.Sn(),
1349 }).Debug("shutting-down-onu")
1350 if err := o.HandleShutdownONU(); err != nil {
1351 return err
1352 }
1353 time.Sleep(timeout)
1354 onuLogger.WithFields(log.Fields{
1355 "IntfId": o.PonPortID,
1356 "OnuId": o.ID,
1357 "SerialNumber": o.Sn(),
1358 }).Debug("power-on-onu")
1359 if err := o.HandlePowerOnONU(); err != nil {
1360 return err
1361 }
1362 return nil
1363}
1364
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001365// BBR methods
1366
1367func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1368 omciMsg := openolt.OmciMsg{
1369 IntfId: intfId,
1370 OnuId: onuId,
1371 Pkt: pktBytes,
1372 }
1373
1374 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1375 log.WithFields(log.Fields{
1376 "IntfId": intfId,
1377 "OnuId": onuId,
1378 "SerialNumber": common.OnuSnToString(sn),
1379 "Pkt": omciMsg.Pkt,
1380 }).Fatalf("Failed to send MIB Reset")
1381 }
1382 log.WithFields(log.Fields{
1383 "IntfId": intfId,
1384 "OnuId": onuId,
1385 "SerialNumber": common.OnuSnToString(sn),
1386 "Pkt": omciMsg.Pkt,
1387 }).Tracef("Sent OMCI message %s", msgType)
1388}
1389
1390func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1391 var next uint16
1392 if len(highPriority) > 0 && highPriority[0] {
1393 next = onu.hpTid
1394 onu.hpTid += 1
1395 if onu.hpTid < 0x8000 {
1396 onu.hpTid = 0x8000
1397 }
1398 } else {
1399 next = onu.tid
1400 onu.tid += 1
1401 if onu.tid >= 0x8000 {
1402 onu.tid = 1
1403 }
1404 }
1405 return next
1406}
1407
1408// TODO move this method in responders/omcisim
Matteo Scandolo8a574812021-05-20 15:18:53 -07001409// StartOmci is called in BBR to start the OMCI state machine
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001410func (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++
Matteo Scandolo8a574812021-05-20 15:18:53 -07001454 // once the mibUpload is complete send a SetRequest for the PPTP to enable the UNI
1455 // NOTE that in BBR we only enable the first UNI
1456 if o.seqNumber == o.MibDb.NumberOfCommands {
1457 meId := omcilib.GenerateUniPortEntityId(1)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001458
Matteo Scandolo8a574812021-05-20 15:18:53 -07001459 meParams := me.ParamData{
1460 EntityID: meId.ToUint16(),
1461 Attributes: me.AttributeValueMap{"AdministrativeState": 0},
1462 }
1463 managedEntity, omciError := me.NewPhysicalPathTerminationPointEthernetUni(meParams)
1464 if omciError.GetError() != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001465 onuLogger.WithFields(log.Fields{
1466 "OnuId": o.ID,
1467 "IntfId": o.PonPortID,
1468 "OnuSn": o.Sn(),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001469 }).Fatal(omciError.GetError())
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001470 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001471
1472 setPPtp, _ := omcilib.CreateSetRequest(managedEntity, 1)
1473 sendOmciMsg(setPPtp, o.PonPortID, o.ID, o.SerialNumber, "setRquest", client)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001474 } else {
1475 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1476 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001477 }
Matteo Scandolo8a574812021-05-20 15:18:53 -07001478 case omci.SetResponseType:
1479 // once we set the PPTP to active we can start sending flows
1480
1481 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
1482 onuLogger.WithFields(log.Fields{
1483 "OnuId": o.ID,
1484 "IntfId": o.PonPortID,
1485 "OnuSn": o.Sn(),
1486 }).Errorf("Error while transitioning ONU State %v", err)
1487 }
1488 case omci.AlarmNotificationType:
1489 log.Info("bbr-received-alarm")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001490 }
1491}
1492
1493func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1494
1495 classifierProto := openolt.Classifier{
1496 EthType: uint32(layers.EthernetTypeEAPOL),
1497 OVid: 4091,
1498 }
1499
1500 actionProto := openolt.Action{}
1501
1502 downstreamFlow := openolt.Flow{
1503 AccessIntfId: int32(o.PonPortID),
1504 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001505 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001506 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001507 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001508 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001509 Classifier: &classifierProto,
1510 Action: &actionProto,
1511 Priority: int32(100),
1512 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001513 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1514 // AllocId and GemPorts need to be unique per PON
1515 // for now use the ONU-ID, will need to change once we support multiple UNIs
1516 AllocId: int32(o.ID),
1517 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001518 }
1519
1520 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1521 log.WithFields(log.Fields{
1522 "IntfId": o.PonPortID,
1523 "OnuId": o.ID,
1524 "FlowId": downstreamFlow.FlowId,
1525 "PortNo": downstreamFlow.PortNo,
1526 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001527 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001528 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001529 }
1530 log.WithFields(log.Fields{
1531 "IntfId": o.PonPortID,
1532 "OnuId": o.ID,
1533 "FlowId": downstreamFlow.FlowId,
1534 "PortNo": downstreamFlow.PortNo,
1535 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1536 }).Info("Sent EAPOL Flow")
1537}
1538
1539func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001540
Matteo Scandolo8a574812021-05-20 15:18:53 -07001541 // BBR only works with a single UNI and a single service (ATT HSIA)
1542 hsia := o.UniPorts[0].(*UniPort).Services[0].(*Service)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001543 classifierProto := openolt.Classifier{
1544 EthType: uint32(layers.EthernetTypeIPv4),
1545 SrcPort: uint32(68),
1546 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001547 OVid: uint32(hsia.CTag),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001548 OPbits: 255,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001549 }
1550
1551 actionProto := openolt.Action{}
1552
1553 downstreamFlow := openolt.Flow{
1554 AccessIntfId: int32(o.PonPortID),
1555 OnuId: int32(o.ID),
Matteo Scandolo8a574812021-05-20 15:18:53 -07001556 UniId: int32(0), // BBR only supports a single UNI
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001557 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001558 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001559 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001560 Classifier: &classifierProto,
1561 Action: &actionProto,
1562 Priority: int32(100),
1563 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001564 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1565 // AllocId and GemPorts need to be unique per PON
1566 // for now use the ONU-ID, will need to change once we support multiple UNIs
1567 AllocId: int32(o.ID),
1568 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001569 }
1570
1571 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1572 log.WithFields(log.Fields{
1573 "IntfId": o.PonPortID,
1574 "OnuId": o.ID,
1575 "FlowId": downstreamFlow.FlowId,
1576 "PortNo": downstreamFlow.PortNo,
1577 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001578 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001579 }).Fatalf("Failed to send DHCP Flow")
1580 }
1581 log.WithFields(log.Fields{
1582 "IntfId": o.PonPortID,
1583 "OnuId": o.ID,
1584 "FlowId": downstreamFlow.FlowId,
1585 "PortNo": downstreamFlow.PortNo,
1586 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1587 }).Info("Sent DHCP Flow")
1588}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301589
1590// DeleteFlow method search and delete flowKey from the onu flows slice
1591func (onu *Onu) DeleteFlow(key FlowKey) {
1592 for pos, flowKey := range onu.Flows {
1593 if flowKey == key {
1594 // delete the flowKey by shifting all flowKeys by one
1595 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1596 t := make([]FlowKey, len(onu.Flows))
1597 copy(t, onu.Flows)
1598 onu.Flows = t
1599 break
1600 }
1601 }
1602}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301603
1604func (onu *Onu) ReDiscoverOnu() {
1605 // Wait for few seconds to be sure of the cleanup
1606 time.Sleep(5 * time.Second)
1607
1608 onuLogger.WithFields(log.Fields{
1609 "IntfId": onu.PonPortID,
1610 "OnuId": onu.ID,
1611 "OnuSn": onu.Sn(),
1612 }).Debug("Send ONU Re-Discovery")
1613
1614 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001615 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301616 log.WithFields(log.Fields{
1617 "IntfId": onu.PonPortID,
1618 "OnuSn": onu.Sn(),
1619 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001620 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301621 }
1622
Matteo Scandolocedde462021-03-09 17:37:16 -08001623 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301624 log.WithFields(log.Fields{
1625 "IntfId": onu.PonPortID,
1626 "OnuSn": onu.Sn(),
1627 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001628 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301629 }
1630}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001631
Matteo Scandolo8a574812021-05-20 15:18:53 -07001632// deprecated, delegate this to the uniPort
Matteo Scandolo4a036262020-08-17 15:56:13 -07001633func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -07001634 // FIXME is there a better way to avoid this loop?
1635 for _, u := range onu.UniPorts {
1636 uni := u.(*UniPort)
1637 for _, s := range uni.Services {
1638 service := s.(*Service)
1639 if service.HwAddress.String() == macAddress.String() {
1640 return service, nil
1641 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001642 }
1643 }
1644 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1645}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301646
Matteo Scandolo8a574812021-05-20 15:18:53 -07001647func (onu *Onu) findUniByPortNo(portNo uint32) (*UniPort, error) {
1648 for _, u := range onu.UniPorts {
1649 uni := u.(*UniPort)
1650 if uni.PortNo == portNo {
1651 return uni, nil
1652 }
1653 }
1654 return nil, fmt.Errorf("cannot-find-uni-with-port-no-%d", portNo)
1655}
1656
Himani Chawla13b1ee02021-03-15 01:43:53 +05301657func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1658 switch alarmType {
1659 case "ONU_ALARM_LOS":
1660 msg := bbsim.Message{
1661 Type: bbsim.UniStatusAlarm,
1662 Data: bbsim.UniStatusAlarmMessage{
1663 OnuSN: o.SerialNumber,
1664 OnuID: o.ID,
1665 EntityID: 257,
1666 RaiseOMCIAlarm: raiseOMCIAlarm,
1667 },
1668 }
1669 o.Channel <- msg
1670 }
1671
1672}
1673
1674func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1675 o.onuAlarmsInfoLock.Lock()
1676 defer o.onuAlarmsInfoLock.Unlock()
1677 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1678 if alarmInfo.SequenceNo == 255 {
1679 alarmInfo.SequenceNo = 1
1680 } else {
1681 alarmInfo.SequenceNo++
1682 }
1683 o.onuAlarmsInfo[key] = alarmInfo
1684 return alarmInfo.SequenceNo
1685 } else {
1686 // This is the first time alarm notification message is being sent
1687 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1688 SequenceNo: 1,
1689 }
1690 return 1
1691 }
1692}