blob: 3ee5a7f762858206e6fbf32660e386aa21bcd82b [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
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700130 StandbyImageVersion string
131 ActiveImageVersion string
132 CommittedImageVersion string
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000133 OmciResponseRate uint8
134 OmciMsgCounter uint8
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800135
136 // OMCI params (Used in BBR)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700137 tid uint16
138 hpTid uint16
139 seqNumber uint16
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700140 MibDb *omcilib.MibDb
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700141
Anand S Katti09541352020-01-29 15:54:01 +0530142 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
143 TrafficSchedulers *tech_profile.TrafficSchedulers
Himani Chawla13b1ee02021-03-15 01:43:53 +0530144 onuAlarmsInfoLock sync.RWMutex
145 onuAlarmsInfo map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700146}
147
Matteo Scandolo99f18462019-10-28 14:14:28 -0700148func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700149 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700150}
151
Matteo Scandolo4a036262020-08-17 15:56:13 -0700152func CreateONU(olt *OltDevice, pon *PonPort, id uint32, delay time.Duration, isMock bool) *Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700153
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700154 o := Onu{
Matteo Scandolocedde462021-03-09 17:37:16 -0800155 ID: id,
156 PonPortID: pon.ID,
157 PonPort: pon,
158 PortNo: 0,
159 tid: 0x1,
160 hpTid: 0x8000,
161 seqNumber: 0,
162 DoneChannel: make(chan bool, 1),
163 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
164 Flows: []FlowKey{},
165 DiscoveryDelay: delay,
166 MibDataSync: 0,
167 ImageSoftwareExpectedSections: 0, // populated during OMCI StartSoftwareDownloadRequest
168 ImageSoftwareReceivedSections: 0,
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700169 //TODO this needs reworking, it's always 0 or 1, possibly base all on the version
170 ActiveImageEntityId: 0, // when we start the SoftwareImage with ID 0 is active and committed
171 CommittedImageEntityId: 0,
172 StandbyImageVersion: "BBSM_IMG_00000",
173 ActiveImageVersion: "BBSM_IMG_00001",
174 CommittedImageVersion: "BBSM_IMG_00001",
175 OmciResponseRate: olt.OmciResponseRate,
176 OmciMsgCounter: 0,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700177 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800178 o.SerialNumber = NewSN(olt.ID, pon.ID, id)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700179 // NOTE this state machine is used to track the operational
180 // state as requested by VOLTHA
181 o.OperState = getOperStateFSM(func(e *fsm.Event) {
182 onuLogger.WithFields(log.Fields{
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700183 "OnuId": o.ID,
184 "IntfId": o.PonPortID,
185 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700186 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
187 })
Himani Chawla13b1ee02021-03-15 01:43:53 +0530188 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700189 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
190 o.InternalState = fsm.NewFSM(
Matteo Scandolocedde462021-03-09 17:37:16 -0800191 OnuStateCreated,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700192 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700193 // DEVICE Lifecycle
Matteo Scandolocedde462021-03-09 17:37:16 -0800194 {Name: OnuTxInitialize, Src: []string{OnuStateCreated, OnuStateDisabled, OnuStatePonDisabled}, Dst: OnuStateInitialized},
195 {Name: OnuTxDiscover, Src: []string{OnuStateInitialized}, Dst: OnuStateDiscovered},
196 {Name: OnuTxEnable, Src: []string{OnuStateDiscovered, OnuStatePonDisabled}, Dst: OnuStateEnabled},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100197 // 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 -0800198 {Name: OnuTxDisable, Src: []string{OnuStateEnabled, OnuStatePonDisabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateDisabled},
Pragya Arya6a708d62020-01-01 17:17:20 +0530199 // 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 +0200200 {Name: OnuTxPonDisable, Src: []string{OnuStateEnabled, OnuStateImageActivated, OnuStateImageDownloadError, OnuStateImageCommitted, OnuStateImageDownloadComplete}, Dst: OnuStatePonDisabled},
Matteo Scandolocedde462021-03-09 17:37:16 -0800201 // Software Image Download related states
Matteo Scandolo9f4bf4f2021-06-22 09:41:02 +0200202 {Name: OnuTxStartImageDownload, Src: []string{OnuStateEnabled, OnuStateImageDownloadComplete, OnuStateImageDownloadError, OnuStateImageCommitted}, Dst: OnuStateImageDownloadStarted},
Matteo Scandolocedde462021-03-09 17:37:16 -0800203 {Name: OnuTxProgressImageDownload, Src: []string{OnuStateImageDownloadStarted}, Dst: OnuStateImageDownloadInProgress},
204 {Name: OnuTxCompleteImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadComplete},
205 {Name: OnuTxFailImageDownload, Src: []string{OnuStateImageDownloadInProgress}, Dst: OnuStateImageDownloadError},
206 {Name: OnuTxActivateImage, Src: []string{OnuStateImageDownloadComplete}, Dst: OnuStateImageActivated},
207 {Name: OnuTxCommitImage, Src: []string{OnuStateEnabled}, Dst: OnuStateImageCommitted}, // the image is committed after a ONU reboot
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700208 // BBR States
209 // TODO add start OMCI state
Matteo Scandolocedde462021-03-09 17:37:16 -0800210 {Name: BbrOnuTxSendEapolFlow, Src: []string{OnuStateInitialized}, Dst: BbrOnuStateEapolFlowSent},
211 {Name: BbrOnuTxSendDhcpFlow, Src: []string{BbrOnuStateEapolFlowSent}, Dst: BbrOnuStateDhcpFlowSent},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700212 },
213 fsm.Callbacks{
214 "enter_state": func(e *fsm.Event) {
215 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700216 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700217 fmt.Sprintf("enter_%s", OnuStateInitialized): func(e *fsm.Event) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100218 // create new channel for ProcessOnuMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800219 o.Channel = make(chan bbsim.Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800220
Matteo Scandolocedde462021-03-09 17:37:16 -0800221 if err := o.OperState.Event(OnuTxEnable); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800222 onuLogger.WithFields(log.Fields{
223 "OnuId": o.ID,
224 "IntfId": o.PonPortID,
225 "OnuSn": o.Sn(),
226 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
227 }
228
Pragya Arya1cbefa42020-01-13 12:15:29 +0530229 if !isMock {
230 // start ProcessOnuMessages Go routine
Matteo Scandolo4a036262020-08-17 15:56:13 -0700231 go o.ProcessOnuMessages(olt.enableContext, olt.OpenoltStream, nil)
Pragya Arya1cbefa42020-01-13 12:15:29 +0530232 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100233 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700234 fmt.Sprintf("enter_%s", OnuStateDiscovered): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800235 msg := bbsim.Message{
236 Type: bbsim.OnuDiscIndication,
237 Data: bbsim.OnuDiscIndicationMessage{
238 OperState: bbsim.UP,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100239 },
240 }
241 o.Channel <- msg
242 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700243 fmt.Sprintf("enter_%s", OnuStateEnabled): func(event *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800244
245 if used, sn := o.PonPort.isOnuIdAllocated(o.ID); used {
246 onuLogger.WithFields(log.Fields{
247 "IntfId": o.PonPortID,
248 "OnuId": o.ID,
249 "SerialNumber": o.Sn(),
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700250 }).Errorf("onu-id-duplicated-with-%s", common.OnuSnToString(sn))
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800251 return
252 } else {
253 o.PonPort.storeOnuId(o.ID, o.SerialNumber)
254 }
255
Matteo Scandolof9d43412021-01-12 11:11:34 -0800256 msg := bbsim.Message{
257 Type: bbsim.OnuIndication,
258 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700259 OnuSN: o.SerialNumber,
260 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800261 OperState: bbsim.UP,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700262 },
263 }
264 o.Channel <- msg
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700265
266 // Once the ONU is enabled start listening for packets
267 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700268 s.Initialize(o.PonPort.Olt.OpenoltStream)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700269 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700270 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700271 fmt.Sprintf("enter_%s", OnuStateDisabled): func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700272
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700273 o.cleanupOnuState()
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700274
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700275 // set the OperState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800276 if err := o.OperState.Event("disable"); err != nil {
277 onuLogger.WithFields(log.Fields{
278 "OnuId": o.ID,
279 "IntfId": o.PonPortID,
280 "OnuSn": o.Sn(),
281 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
282 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700283 // send the OnuIndication DOWN event
Matteo Scandolof9d43412021-01-12 11:11:34 -0800284 msg := bbsim.Message{
285 Type: bbsim.OnuIndication,
286 Data: bbsim.OnuIndicationMessage{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700287 OnuSN: o.SerialNumber,
288 PonPortID: o.PonPortID,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800289 OperState: bbsim.DOWN,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700290 },
291 }
292 o.Channel <- msg
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530293
294 // verify all the flows removes are handled and
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100295 // terminate the ONU's ProcessOnuMessages Go routine
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530296 if len(o.FlowIds) == 0 {
297 close(o.Channel)
298 }
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700299
300 for _, s := range o.Services {
301 s.Disable()
302 }
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700303
304 },
305 fmt.Sprintf("enter_%s", OnuStatePonDisabled): func(event *fsm.Event) {
306 o.cleanupOnuState()
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700307 },
Matteo Scandolo4a036262020-08-17 15:56:13 -0700308 // BBR states
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700309 fmt.Sprintf("enter_%s", BbrOnuStateEapolFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800310 msg := bbsim.Message{
311 Type: bbsim.SendEapolFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700312 }
313 o.Channel <- msg
314 },
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700315 fmt.Sprintf("enter_%s", BbrOnuStateDhcpFlowSent): func(e *fsm.Event) {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800316 msg := bbsim.Message{
317 Type: bbsim.SendDhcpFlow,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700318 }
319 o.Channel <- msg
320 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700321 },
322 )
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100323
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700324 for i := 0; i < uniPorts; i++ {
325 uni, err := NewUniPort(uint32(i), &o)
326 if err != nil {
327 onuLogger.WithFields(log.Fields{
328 "OnuId": o.ID,
329 "IntfId": o.PonPortID,
330 "OnuSn": o.Sn(),
331 "Err": err,
332 }).Fatal("cannot-create-uni-port")
333 }
334 o.UniPorts = append(o.UniPorts, uni)
335 }
336
337 mibDb, err := omcilib.GenerateMibDatabase(len(o.UniPorts))
338 if err != nil {
339 onuLogger.WithFields(log.Fields{
340 "OnuId": o.ID,
341 "IntfId": o.PonPortID,
342 "OnuSn": o.Sn(),
343 }).Fatal("cannot-generate-mibdb-for-onu")
344 }
345 o.MibDb = mibDb
346
Matteo Scandolo27428702019-10-11 16:21:16 -0700347 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700348}
349
William Kurkian0418bc82019-11-06 12:16:24 -0500350func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700351 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700352 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700353 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700354 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700355 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
356}
357
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700358// cleanupOnuState this method is to clean the local state when the ONU is disabled
359func (o *Onu) cleanupOnuState() {
360 // clean the ONU state
361 o.PortNo = 0
362 o.Flows = []FlowKey{}
363 o.PonPort.removeOnuId(o.ID)
364 o.PonPort.removeAllocId(o.SerialNumber)
365 o.PonPort.removeGemPortBySn(o.SerialNumber)
366
367 o.onuAlarmsInfoLock.Lock()
368 o.onuAlarmsInfo = make(map[omcilib.OnuAlarmInfoMapKey]omcilib.OnuAlarmInfo) //Basically reset everything on onu disable
369 o.onuAlarmsInfoLock.Unlock()
370}
371
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100372// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000373func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700374 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100375 "onuID": o.ID,
376 "onuSN": o.Sn(),
377 "ponPort": o.PonPortID,
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700378 "stream": stream,
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100379 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700380
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700381 defer onuLogger.WithFields(log.Fields{
382 "onuID": o.ID,
383 "onuSN": o.Sn(),
384 "stream": stream,
385 }).Debug("Stopped handling ONU Indication Channel")
386
David Bainbridge103cf022019-12-16 20:11:35 +0000387loop:
388 for {
389 select {
390 case <-ctx.Done():
391 onuLogger.WithFields(log.Fields{
392 "onuID": o.ID,
393 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700394 }).Debug("ONU message handling canceled via context")
395 break loop
396 case <-stream.Context().Done():
397 onuLogger.WithFields(log.Fields{
398 "onuID": o.ID,
399 "onuSN": o.Sn(),
400 }).Debug("ONU message handling canceled via stream context")
David Bainbridge103cf022019-12-16 20:11:35 +0000401 break loop
402 case message, ok := <-o.Channel:
403 if !ok || ctx.Err() != nil {
404 onuLogger.WithFields(log.Fields{
405 "onuID": o.ID,
406 "onuSN": o.Sn(),
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700407 }).Debug("ONU message handling canceled via channel close")
David Bainbridge103cf022019-12-16 20:11:35 +0000408 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700409 }
David Bainbridge103cf022019-12-16 20:11:35 +0000410 onuLogger.WithFields(log.Fields{
411 "onuID": o.ID,
412 "onuSN": o.Sn(),
413 "messageType": message.Type,
414 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700415
David Bainbridge103cf022019-12-16 20:11:35 +0000416 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800417 case bbsim.OnuDiscIndication:
418 msg, _ := message.Data.(bbsim.OnuDiscIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000419 // 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 +0530420 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000421 o.sendOnuDiscIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800422 case bbsim.OnuIndication:
423 msg, _ := message.Data.(bbsim.OnuIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000424 o.sendOnuIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800425 case bbsim.OMCI:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800426 // these are OMCI messages received by the ONU
Matteo Scandolof9d43412021-01-12 11:11:34 -0800427 msg, _ := message.Data.(bbsim.OmciMessage)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200428 _ = o.handleOmciRequest(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800429 case bbsim.UniStatusAlarm:
430 msg, _ := message.Data.(bbsim.UniStatusAlarmMessage)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530431 onuAlarmMapKey := omcilib.OnuAlarmInfoMapKey{
432 MeInstance: msg.EntityID,
433 MeClassID: me.PhysicalPathTerminationPointEthernetUniClassID,
434 }
435 seqNo := o.IncrementAlarmSequenceNumber(onuAlarmMapKey)
436 o.onuAlarmsInfoLock.Lock()
437 var alarmInfo = o.onuAlarmsInfo[onuAlarmMapKey]
438 pkt, alarmBitMap := omcilib.CreateUniStatusAlarm(msg.RaiseOMCIAlarm, msg.EntityID, seqNo)
439 if pkt != nil { //pkt will be nil if we are unable to create the alarm
440 if err := o.sendOmciIndication(pkt, 0, stream); err != nil {
441 onuLogger.WithFields(log.Fields{
442 "IntfId": o.PonPortID,
443 "SerialNumber": o.Sn(),
444 "omciPacket": pkt,
445 "adminState": msg.AdminState,
446 "entityID": msg.EntityID,
447 }).Errorf("failed-to-send-UNI-Link-Alarm: %v", err)
448 alarmInfo.SequenceNo--
449 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800450 onuLogger.WithFields(log.Fields{
451 "IntfId": o.PonPortID,
452 "SerialNumber": o.Sn(),
453 "omciPacket": pkt,
454 "adminState": msg.AdminState,
455 "entityID": msg.EntityID,
Himani Chawla13b1ee02021-03-15 01:43:53 +0530456 }).Trace("UNI-Link-alarm-sent")
457 if alarmBitMap == [28]byte{0} {
458 delete(o.onuAlarmsInfo, onuAlarmMapKey)
459 } else {
460 alarmInfo.AlarmBitMap = alarmBitMap
461 o.onuAlarmsInfo[onuAlarmMapKey] = alarmInfo
462 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800463 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530464 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800465 case bbsim.FlowAdd:
466 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700467 o.handleFlowAdd(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800468 case bbsim.FlowRemoved:
469 msg, _ := message.Data.(bbsim.OnuFlowUpdateMessage)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700470 o.handleFlowRemove(msg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800471 case bbsim.OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700472
Matteo Scandolof9d43412021-01-12 11:11:34 -0800473 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000474
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700475 onuLogger.WithFields(log.Fields{
David Bainbridge103cf022019-12-16 20:11:35 +0000476 "IntfId": msg.IntfId,
477 "OnuId": msg.OnuId,
478 "pktType": msg.Type,
479 }).Trace("Received OnuPacketOut Message")
480
Matteo Scandolo618a6582020-09-09 12:21:29 -0700481 if msg.Type == packetHandlers.EAPOL || msg.Type == packetHandlers.DHCP {
482
483 service, err := o.findServiceByMacAddress(msg.MacAddress)
484 if err != nil {
485 onuLogger.WithFields(log.Fields{
486 "IntfId": msg.IntfId,
487 "OnuId": msg.OnuId,
488 "pktType": msg.Type,
489 "MacAddress": msg.MacAddress,
490 "Pkt": hex.EncodeToString(msg.Packet.Data()),
491 "OnuSn": o.Sn(),
492 }).Error("Cannot find Service associated with packet")
493 return
494 }
495 service.PacketCh <- msg
496 } else if msg.Type == packetHandlers.IGMP {
497 // if it's an IGMP packet we assume we have a single IGMP service
498 for _, s := range o.Services {
499 service := s.(*Service)
500
501 if service.NeedsIgmp {
502 service.PacketCh <- msg
503 }
504 }
David Bainbridge103cf022019-12-16 20:11:35 +0000505 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700506
Matteo Scandolof9d43412021-01-12 11:11:34 -0800507 case bbsim.OnuPacketIn:
David Bainbridge103cf022019-12-16 20:11:35 +0000508 // NOTE we only receive BBR packets here.
509 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
510 // 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 -0800511 msg, _ := message.Data.(bbsim.OnuPacketMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000512
513 log.WithFields(log.Fields{
514 "IntfId": msg.IntfId,
515 "OnuId": msg.OnuId,
516 "pktType": msg.Type,
517 }).Trace("Received OnuPacketIn Message")
518
519 if msg.Type == packetHandlers.EAPOL {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700520 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 +0000521 } else if msg.Type == packetHandlers.DHCP {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700522 _ = dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.DoneChannel, msg.Packet, client)
David Bainbridge103cf022019-12-16 20:11:35 +0000523 }
Matteo Scandolo7f656fb2020-09-08 15:18:15 -0700524 // BBR specific messages
Matteo Scandolof9d43412021-01-12 11:11:34 -0800525 case bbsim.OmciIndication:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800526 // these are OMCI messages received by BBR (VOLTHA emulator)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800527 msg, _ := message.Data.(bbsim.OmciIndicationMessage)
528 o.handleOmciResponse(msg, client)
529 case bbsim.SendEapolFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000530 o.sendEapolFlow(client)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800531 case bbsim.SendDhcpFlow:
David Bainbridge103cf022019-12-16 20:11:35 +0000532 o.sendDhcpFlow(client)
533 default:
534 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700535 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700536 }
537 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700538}
539
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800540func NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700541 sn := new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700542 sn.VendorId = []byte("BBSM")
543 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700544 return sn
545}
546
Matteo Scandolof9d43412021-01-12 11:11:34 -0800547func (o *Onu) sendOnuDiscIndication(msg bbsim.OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700548 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800549 IntfId: o.PonPortID,
550 SerialNumber: o.SerialNumber,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700551 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700552
Matteo Scandolo4747d292019-08-05 11:50:18 -0700553 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700554 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700555 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700556 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700557
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700558 onuLogger.WithFields(log.Fields{
Matteo Scandolof9d43412021-01-12 11:11:34 -0800559 "IntfId": o.PonPortID,
560 "OnuSn": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700561 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700562 }).Debug("Sent Indication_OnuDiscInd")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800563 publishEvent("ONU-discovery-indication-sent", int32(o.PonPortID), int32(o.ID), o.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800564
565 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
566 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800567 time.Sleep(delay)
Matteo Scandolocedde462021-03-09 17:37:16 -0800568 if o.InternalState.Current() == OnuStateDiscovered {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800569 o.sendOnuDiscIndication(msg, stream)
570 }
571 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700572}
573
Matteo Scandolof9d43412021-01-12 11:11:34 -0800574func (o *Onu) sendOnuIndication(msg bbsim.OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800575 // NOTE the ONU ID is set by VOLTHA in the ActivateOnu call (via openolt.proto)
576 // and stored in the Onu struct via onu.SetID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700577
578 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700579 IntfId: o.PonPortID,
580 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700581 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700582 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700583 SerialNumber: o.SerialNumber,
584 }}
585 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800586 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700587 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700588 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700589 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700590 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800591 "IntfId": o.PonPortID,
592 "OnuId": o.ID,
593 "VolthaOnuId": msg.OnuID,
594 "OperState": msg.OperState.String(),
595 "AdminState": msg.OperState.String(),
596 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700597 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700598
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700599}
600
Matteo Scandolof9d43412021-01-12 11:11:34 -0800601func (o *Onu) HandleShutdownONU() error {
602
603 dyingGasp := pb.ONUAlarmRequest{
604 AlarmType: "DYING_GASP",
605 SerialNumber: o.Sn(),
606 Status: "on",
607 }
608
609 if err := alarmsim.SimulateOnuAlarm(&dyingGasp, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
610 onuLogger.WithFields(log.Fields{
611 "OnuId": o.ID,
612 "IntfId": o.PonPortID,
613 "OnuSn": o.Sn(),
614 }).Errorf("Cannot send Dying Gasp: %s", err.Error())
615 return err
616 }
617
618 losReq := pb.ONUAlarmRequest{
619 AlarmType: "ONU_ALARM_LOS",
620 SerialNumber: o.Sn(),
621 Status: "on",
622 }
623
624 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
625 onuLogger.WithFields(log.Fields{
626 "OnuId": o.ID,
627 "IntfId": o.PonPortID,
628 "OnuSn": o.Sn(),
629 }).Errorf("Cannot send LOS: %s", err.Error())
630
631 return err
632 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530633 o.SendOMCIAlarmNotificationMsg(true, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800634 // TODO if it's the last ONU on the PON, then send a PON LOS
635
Matteo Scandolocedde462021-03-09 17:37:16 -0800636 if err := o.InternalState.Event(OnuTxDisable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800637 onuLogger.WithFields(log.Fields{
638 "OnuId": o.ID,
639 "IntfId": o.PonPortID,
640 "OnuSn": o.Sn(),
641 }).Errorf("Cannot shutdown ONU: %s", err.Error())
642 return err
643 }
644
645 return nil
646}
647
648func (o *Onu) HandlePowerOnONU() error {
649 intitalState := o.InternalState.Current()
650
651 // initialize the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800652 if intitalState == OnuStateCreated || intitalState == OnuStateDisabled {
653 if err := o.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800654 onuLogger.WithFields(log.Fields{
655 "OnuId": o.ID,
656 "IntfId": o.PonPortID,
657 "OnuSn": o.Sn(),
658 }).Errorf("Cannot poweron ONU: %s", err.Error())
659 return err
660 }
661 }
662
663 // turn off the LOS Alarm
664 losReq := pb.ONUAlarmRequest{
665 AlarmType: "ONU_ALARM_LOS",
666 SerialNumber: o.Sn(),
667 Status: "off",
668 }
669
670 if err := alarmsim.SimulateOnuAlarm(&losReq, o.ID, o.PonPortID, o.PonPort.Olt.channel); err != nil {
671 onuLogger.WithFields(log.Fields{
672 "OnuId": o.ID,
673 "IntfId": o.PonPortID,
674 "OnuSn": o.Sn(),
675 }).Errorf("Cannot send LOS: %s", err.Error())
676 return err
677 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530678 o.SendOMCIAlarmNotificationMsg(false, losReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800679
680 // Send a ONU Discovery indication
Matteo Scandolocedde462021-03-09 17:37:16 -0800681 if err := o.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800682 onuLogger.WithFields(log.Fields{
683 "OnuId": o.ID,
684 "IntfId": o.PonPortID,
685 "OnuSn": o.Sn(),
686 }).Errorf("Cannot poweron ONU: %s", err.Error())
687 return err
688 }
689
690 // move o directly to enable state only when its a powercycle case
691 // in case of first time o poweron o will be moved to enable on
692 // receiving ActivateOnu request from openolt adapter
Matteo Scandolocedde462021-03-09 17:37:16 -0800693 if intitalState == OnuStateDisabled {
694 if err := o.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800695 onuLogger.WithFields(log.Fields{
696 "OnuId": o.ID,
697 "IntfId": o.PonPortID,
698 "OnuSn": o.Sn(),
699 }).Errorf("Cannot enable ONU: %s", err.Error())
700 return err
701 }
702 }
703
704 return nil
705}
706
707func (o *Onu) SetAlarm(alarmType string, status string) error {
708 alarmReq := pb.ONUAlarmRequest{
709 AlarmType: alarmType,
710 SerialNumber: o.Sn(),
711 Status: status,
712 }
713
714 err := alarmsim.SimulateOnuAlarm(&alarmReq, o.ID, o.PonPortID, o.PonPort.Olt.channel)
715 if err != nil {
716 return err
717 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530718 raiseAlarm := false
719 if alarmReq.Status == "on" {
720 raiseAlarm = true
721 }
722 o.SendOMCIAlarmNotificationMsg(raiseAlarm, alarmReq.AlarmType)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800723 return nil
724}
725
726func (o *Onu) publishOmciEvent(msg bbsim.OmciMessage) {
Pragya Arya324337e2020-02-20 14:35:08 +0530727 if olt.PublishEvents {
Matteo Scandolob5913142021-03-19 16:10:18 -0700728 _, omciMsg, err := omcilib.ParseOpenOltOmciPacket(msg.OmciPkt.Data())
Pragya Arya324337e2020-02-20 14:35:08 +0530729 if err != nil {
730 log.Errorf("error in getting msgType %v", err)
731 return
732 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800733 if omciMsg.MessageType == omci.MibUploadRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530734 o.seqNumber = 0
735 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
Matteo Scandolof9d43412021-01-12 11:11:34 -0800736 } else if omciMsg.MessageType == omci.MibUploadNextRequestType {
Pragya Arya324337e2020-02-20 14:35:08 +0530737 o.seqNumber++
738 if o.seqNumber > 290 {
739 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
740 }
741 }
742 }
743}
744
Matteo Scandolof9d43412021-01-12 11:11:34 -0800745// handleOmciRequest is responsible to parse the OMCI packets received from the openolt adapter
746// and generate the appropriate response to it
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200747func (o *Onu) handleOmciRequest(msg bbsim.OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800748
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700749 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -0700750 "omciMsgType": msg.OmciMsg.MessageType,
751 "transCorrId": strconv.FormatInt(int64(msg.OmciMsg.TransactionID), 16),
752 "DeviceIdent": msg.OmciMsg.DeviceIdentifier,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700753 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700754 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -0800755 }).Trace("omci-message-decoded")
756
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000757 if o.OmciMsgCounter < maxOmciMsgCounter {
758 o.OmciMsgCounter++
759 } else {
760 o.OmciMsgCounter = 1
761 }
762 if o.OmciMsgCounter > o.OmciResponseRate {
763 onuLogger.WithFields(log.Fields{
764 "OmciMsgCounter": o.OmciMsgCounter,
765 "OmciResponseRate": o.OmciResponseRate,
766 "omciMsgType": msg.OmciMsg.MessageType,
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +0200767 }).Debug("skipping-omci-msg-response")
768 return fmt.Errorf("skipping-omci-msg-response-because-of-response-rate-%d", o.OmciResponseRate)
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000769 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800770 var responsePkt []byte
Girish Gowdrae2683102021-03-05 08:24:26 -0800771 var errResp error
Matteo Scandolob5913142021-03-19 16:10:18 -0700772 switch msg.OmciMsg.MessageType {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800773 case omci.MibResetRequestType:
Matteo Scandolo992a23e2021-02-04 15:35:04 -0800774 onuLogger.WithFields(log.Fields{
775 "IntfId": o.PonPortID,
776 "OnuId": o.ID,
777 "SerialNumber": o.Sn(),
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700778 }).Debug("received-mib-reset-request")
Matteo Scandolob5913142021-03-19 16:10:18 -0700779 if responsePkt, errResp = omcilib.CreateMibResetResponse(msg.OmciMsg.TransactionID); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800780 o.MibDataSync = 0
Matteo Scandolo2fdc3b82021-04-23 15:27:21 -0700781
782 // if the MIB reset is successful then remove all the stored AllocIds and GemPorts
783 o.PonPort.removeAllocId(o.SerialNumber)
784 o.PonPort.removeGemPortBySn(o.SerialNumber)
Girish Gowdrae2683102021-03-05 08:24:26 -0800785 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800786 case omci.MibUploadRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700787 responsePkt, _ = omcilib.CreateMibUploadResponse(msg.OmciMsg.TransactionID, o.MibDb.NumberOfCommands)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800788 case omci.MibUploadNextRequestType:
Matteo Scandoloef4e8f82021-05-17 11:20:49 -0700789 responsePkt, _ = omcilib.CreateMibUploadNextResponse(msg.OmciPkt, msg.OmciMsg, o.MibDataSync, o.MibDb)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800790 case omci.GetRequestType:
Girish Gowdra996d81e2021-04-21 16:16:27 -0700791 onuDown := o.OperState.Current() == "down"
Matteo Scandoloc00e97a2021-05-27 11:45:27 -0700792 responsePkt, _ = omcilib.CreateGetResponse(msg.OmciPkt, msg.OmciMsg, o.SerialNumber, o.MibDataSync, o.ActiveImageEntityId,
793 o.CommittedImageEntityId, o.StandbyImageVersion, o.ActiveImageVersion, o.CommittedImageVersion, onuDown)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800794 case omci.SetRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800795 success := true
Matteo Scandolob5913142021-03-19 16:10:18 -0700796 msgObj, _ := omcilib.ParseSetRequest(msg.OmciPkt)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800797 switch msgObj.EntityClass {
798 case me.PhysicalPathTerminationPointEthernetUniClassID:
799 // if we're Setting a PPTP state
800 // we need to send the appropriate alarm
801
802 if msgObj.EntityInstance == 257 {
803 // for now we're only caring about the first UNI
804 // NOTE that the EntityID for the UNI port is for now hardcoded in
805 // omci/mibpackets.go where the PhysicalPathTerminationPointEthernetUni
806 // are reported during the MIB Upload sequence
807 adminState := msgObj.Attributes["AdministrativeState"].(uint8)
Himani Chawla13b1ee02021-03-15 01:43:53 +0530808 raiseOMCIAlarm := false
809 if adminState == 1 {
810 raiseOMCIAlarm = true
Girish Gowdra996d81e2021-04-21 16:16:27 -0700811 // set the OperState to disabled
812 if err := o.OperState.Event(OnuTxDisable); err != nil {
813 onuLogger.WithFields(log.Fields{
814 "OnuId": o.ID,
815 "IntfId": o.PonPortID,
816 "OnuSn": o.Sn(),
817 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
818 }
819 } else {
820 // set the OperState to enabled
821 if err := o.OperState.Event(OnuTxEnable); err != nil {
822 onuLogger.WithFields(log.Fields{
823 "OnuId": o.ID,
824 "IntfId": o.PonPortID,
825 "OnuSn": o.Sn(),
826 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
827 }
Himani Chawla13b1ee02021-03-15 01:43:53 +0530828 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800829 msg := bbsim.Message{
830 Type: bbsim.UniStatusAlarm,
831 Data: bbsim.UniStatusAlarmMessage{
Himani Chawla13b1ee02021-03-15 01:43:53 +0530832 OnuSN: o.SerialNumber,
833 OnuID: o.ID,
834 AdminState: adminState,
835 EntityID: msgObj.EntityInstance,
836 RaiseOMCIAlarm: raiseOMCIAlarm,
Matteo Scandolof9d43412021-01-12 11:11:34 -0800837 },
838 }
839 o.Channel <- msg
840 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800841 case me.TContClassID:
842 allocId := msgObj.Attributes["AllocId"].(uint16)
843
844 // if the AllocId is 255 (0xFF) or 65535 (0xFFFF) it means we are removing it,
845 // otherwise we are adding it
846 if allocId == 255 || allocId == 65535 {
847 onuLogger.WithFields(log.Fields{
848 "IntfId": o.PonPortID,
849 "OnuId": o.ID,
850 "TContId": msgObj.EntityInstance,
851 "AllocId": allocId,
852 "SerialNumber": o.Sn(),
853 }).Trace("freeing-alloc-id-via-omci")
854 o.PonPort.removeAllocId(o.SerialNumber)
855 } else {
856 if used, sn := o.PonPort.isAllocIdAllocated(allocId); used {
857 onuLogger.WithFields(log.Fields{
858 "IntfId": o.PonPortID,
859 "OnuId": o.ID,
860 "AllocId": allocId,
861 "SerialNumber": o.Sn(),
862 }).Errorf("allocid-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
863 success = false
864 } else {
865 onuLogger.WithFields(log.Fields{
866 "IntfId": o.PonPortID,
867 "OnuId": o.ID,
868 "TContId": msgObj.EntityInstance,
869 "AllocId": allocId,
870 "SerialNumber": o.Sn(),
871 }).Trace("storing-alloc-id-via-omci")
872 o.PonPort.storeAllocId(allocId, o.SerialNumber)
873 }
874 }
875
876 }
877
878 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -0700879 if responsePkt, errResp = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800880 o.MibDataSync++
881 }
882 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700883 responsePkt, _ = omcilib.CreateSetResponse(msg.OmciPkt, msg.OmciMsg, me.AttributeFailure)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800884 }
885 case omci.CreateRequestType:
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800886 // check for GemPortNetworkCtp and make sure there are no duplicates on the same PON
887 var used bool
888 var sn *openolt.SerialNumber
Matteo Scandolob5913142021-03-19 16:10:18 -0700889 msgObj, err := omcilib.ParseCreateRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800890 if err == nil {
891 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
Matteo Scandolo973b0182021-04-08 11:24:42 -0700892 // GemPort 4069 is reserved for multicast and shared across ONUs
893 if msgObj.EntityInstance != 4069 {
894 if used, sn = o.PonPort.isGemPortAllocated(msgObj.EntityInstance); used {
895 onuLogger.WithFields(log.Fields{
896 "IntfId": o.PonPortID,
897 "OnuId": o.ID,
898 "GemPortId": msgObj.EntityInstance,
899 "SerialNumber": o.Sn(),
900 }).Errorf("gemport-already-allocated-to-onu-with-sn-%s", common.OnuSnToString(sn))
901 } else {
902 onuLogger.WithFields(log.Fields{
903 "IntfId": o.PonPortID,
904 "OnuId": o.ID,
905 "GemPortId": msgObj.EntityInstance,
906 "SerialNumber": o.Sn(),
907 }).Trace("storing-gem-port-id-via-omci")
908 o.PonPort.storeGemPort(msgObj.EntityInstance, o.SerialNumber)
909 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800910 }
911 }
912 }
913
914 // if the gemPort is valid then increment the MDS and return a successful response
915 // otherwise fail the request
916 // for now the CreateRequeste for the gemPort is the only one that can fail, if we start supporting multiple
917 // validation this check will need to be rewritten
918 if !used {
Matteo Scandolob5913142021-03-19 16:10:18 -0700919 if responsePkt, errResp = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800920 o.MibDataSync++
921 }
922 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -0700923 responsePkt, _ = omcilib.CreateCreateResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError)
Girish Gowdrae2683102021-03-05 08:24:26 -0800924 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800925 case omci.DeleteRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -0700926 msgObj, err := omcilib.ParseDeleteRequest(msg.OmciPkt)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800927 if err == nil {
928 if msgObj.EntityClass == me.GemPortNetworkCtpClassID {
929 onuLogger.WithFields(log.Fields{
930 "IntfId": o.PonPortID,
931 "OnuId": o.ID,
932 "GemPortId": msgObj.EntityInstance,
933 "SerialNumber": o.Sn(),
934 }).Trace("freeing-gem-port-id-via-omci")
935 o.PonPort.removeGemPort(msgObj.EntityInstance)
936 }
937 }
938
Matteo Scandolob5913142021-03-19 16:10:18 -0700939 if responsePkt, errResp = omcilib.CreateDeleteResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Girish Gowdrae2683102021-03-05 08:24:26 -0800940 o.MibDataSync++
941 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800942 case omci.RebootRequestType:
943
Matteo Scandolob5913142021-03-19 16:10:18 -0700944 responsePkt, _ = omcilib.CreateRebootResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800945
946 // powercycle the ONU
Matteo Scandolocedde462021-03-09 17:37:16 -0800947 // we run this in a separate goroutine so that
948 // the RebootRequestResponse is sent to VOLTHA
Matteo Scandolof9d43412021-01-12 11:11:34 -0800949 go func() {
Matteo Scandolocedde462021-03-09 17:37:16 -0800950 if err := o.Reboot(10 * time.Second); err != nil {
951 log.WithFields(log.Fields{
952 "IntfId": o.PonPortID,
953 "OnuId": o.ID,
954 "SerialNumber": o.Sn(),
955 "err": err,
956 }).Error("cannot-reboot-onu-after-omci-reboot-request")
957 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800958 }()
959 case omci.TestRequestType:
Girish Gowdra161d27a2021-05-05 12:01:44 -0700960 var classID me.ClassID
961 var omciResult me.Results
962 var instID uint16
963 responsePkt, errResp, classID, instID, omciResult = omcilib.CreateTestResponse(msg.OmciPkt, msg.OmciMsg)
964 // Send TestResult only in case the TestResponse omci result code is me.Success
965 if responsePkt != nil && errResp == nil && omciResult == me.Success {
966 if testResultPkt, err := omcilib.CreateTestResult(classID, instID, msg.OmciMsg.TransactionID); err == nil {
967 // send test results asynchronously
968 go func() {
969 // Send test results after a second to emulate async behavior
970 time.Sleep(1 * time.Second)
971 if testResultPkt != nil {
972 if err := o.sendOmciIndication(testResultPkt, msg.OmciMsg.TransactionID, stream); err != nil {
973 onuLogger.WithFields(log.Fields{
974 "IntfId": o.PonPortID,
975 "SerialNumber": o.Sn(),
976 "omciPacket": testResultPkt,
977 "msg.OmciMsgType": msg.OmciMsg.MessageType,
978 "transCorrId": msg.OmciMsg.TransactionID,
979 }).Errorf("failed-to-send-omci-message: %v", err)
980 }
981 }
982 }()
Matteo Scandolof9d43412021-01-12 11:11:34 -0800983 }
984 }
Girish Gowdraa539f522021-02-15 23:00:45 -0800985 case omci.SynchronizeTimeRequestType:
986 // MDS counter increment is not required for this message type
Matteo Scandolob5913142021-03-19 16:10:18 -0700987 responsePkt, _ = omcilib.CreateSyncTimeResponse(msg.OmciPkt, msg.OmciMsg)
Matteo Scandolocedde462021-03-09 17:37:16 -0800988 case omci.StartSoftwareDownloadRequestType:
989
990 o.ImageSoftwareReceivedSections = 0
991
Matteo Scandolob5913142021-03-19 16:10:18 -0700992 o.ImageSoftwareExpectedSections = omcilib.ComputeDownloadSectionsCount(msg.OmciPkt)
Matteo Scandolocedde462021-03-09 17:37:16 -0800993
Matteo Scandolob5913142021-03-19 16:10:18 -0700994 if responsePkt, errResp = omcilib.CreateStartSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -0800995 o.MibDataSync++
996 if err := o.InternalState.Event(OnuTxStartImageDownload); err != nil {
997 onuLogger.WithFields(log.Fields{
998 "OnuId": o.ID,
999 "IntfId": o.PonPortID,
1000 "OnuSn": o.Sn(),
1001 "Err": err.Error(),
1002 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadStarted)
1003 }
1004 } else {
1005 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001006 "OmciMsgType": msg.OmciMsg.MessageType,
1007 "TransCorrId": msg.OmciMsg.TransactionID,
1008 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001009 "IntfId": o.PonPortID,
1010 "SerialNumber": o.Sn(),
1011 }).Error("error-while-processing-start-software-download-request")
1012 }
1013 case omci.DownloadSectionRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001014 if msgObj, err := omcilib.ParseDownloadSectionRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001015 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001016 "OmciMsgType": msg.OmciMsg.MessageType,
1017 "TransCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001018 "EntityInstance": msgObj.EntityInstance,
1019 "SectionNumber": msgObj.SectionNumber,
1020 "SectionData": msgObj.SectionData,
1021 }).Trace("received-download-section-request")
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001022 //Extracting the first 14 bytes to use as a version for this image.
1023 if o.ImageSoftwareReceivedSections == 0 {
1024 o.StandbyImageVersion = string(msgObj.SectionData[0:14])
1025 }
Matteo Scandolocedde462021-03-09 17:37:16 -08001026 o.ImageSoftwareReceivedSections++
1027 if o.InternalState.Current() != OnuStateImageDownloadInProgress {
1028 if err := o.InternalState.Event(OnuTxProgressImageDownload); err != nil {
1029 onuLogger.WithFields(log.Fields{
1030 "OnuId": o.ID,
1031 "IntfId": o.PonPortID,
1032 "OnuSn": o.Sn(),
1033 "Err": err.Error(),
1034 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadInProgress)
1035 }
1036 }
1037 }
1038 case omci.DownloadSectionRequestWithResponseType:
1039 // NOTE we only need to respond if an ACK is requested
Matteo Scandolob5913142021-03-19 16:10:18 -07001040 responsePkt, errResp = omcilib.CreateDownloadSectionResponse(msg.OmciPkt, msg.OmciMsg)
1041 if errResp != nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001042 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001043 "OmciMsgType": msg.OmciMsg.MessageType,
1044 "TransCorrId": msg.OmciMsg.TransactionID,
1045 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001046 "IntfId": o.PonPortID,
1047 "SerialNumber": o.Sn(),
1048 }).Error("error-while-processing-create-download-section-response")
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001049 return fmt.Errorf("error-while-processing-create-download-section-response: %s", errResp.Error())
Matteo Scandolocedde462021-03-09 17:37:16 -08001050 }
1051 o.ImageSoftwareReceivedSections++
1052
1053 case omci.EndSoftwareDownloadRequestType:
1054
1055 // In the startSoftwareDownload we get the image size and the window size.
1056 // We calculate how many DownloadSection we should receive and validate
1057 // that we got the correct amount when we receive this message
1058 success := true
1059 if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
1060 onuLogger.WithFields(log.Fields{
1061 "OnuId": o.ID,
1062 "IntfId": o.PonPortID,
1063 "OnuSn": o.Sn(),
1064 "ExpectedSections": o.ImageSoftwareExpectedSections,
1065 "ReceivedSections": o.ImageSoftwareReceivedSections,
1066 }).Errorf("onu-did-not-receive-all-image-sections")
1067 success = false
1068 }
1069
1070 if success {
Matteo Scandolob5913142021-03-19 16:10:18 -07001071 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001072 o.MibDataSync++
1073 if err := o.InternalState.Event(OnuTxCompleteImageDownload); err != nil {
1074 onuLogger.WithFields(log.Fields{
1075 "OnuId": o.ID,
1076 "IntfId": o.PonPortID,
1077 "OnuSn": o.Sn(),
1078 "Err": err.Error(),
1079 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadComplete)
1080 }
1081 } else {
1082 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001083 "OmciMsgType": msg.OmciMsg.MessageType,
1084 "TransCorrId": msg.OmciMsg.TransactionID,
1085 "Err": errResp.Error(),
Matteo Scandolocedde462021-03-09 17:37:16 -08001086 "IntfId": o.PonPortID,
1087 "SerialNumber": o.Sn(),
1088 }).Error("error-while-processing-end-software-download-request")
1089 }
1090 } else {
Matteo Scandolob5913142021-03-19 16:10:18 -07001091 if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001092 if err := o.InternalState.Event(OnuTxFailImageDownload); err != nil {
1093 onuLogger.WithFields(log.Fields{
1094 "OnuId": o.ID,
1095 "IntfId": o.PonPortID,
1096 "OnuSn": o.Sn(),
1097 "Err": err.Error(),
1098 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageDownloadError)
1099 }
1100 }
1101 }
1102
1103 case omci.ActivateSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001104 if responsePkt, errResp = omcilib.CreateActivateSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001105 o.MibDataSync++
1106 if err := o.InternalState.Event(OnuTxActivateImage); err != nil {
1107 onuLogger.WithFields(log.Fields{
1108 "OnuId": o.ID,
1109 "IntfId": o.PonPortID,
1110 "OnuSn": o.Sn(),
1111 "Err": err.Error(),
1112 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageActivated)
1113 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001114 if msgObj, err := omcilib.ParseActivateSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001115 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001116 previousActiveImage := o.ActiveImageVersion
1117 o.ActiveImageVersion = o.StandbyImageVersion
1118 o.StandbyImageVersion = previousActiveImage
Matteo Scandolocedde462021-03-09 17:37:16 -08001119 } else {
1120 onuLogger.Errorf("something-went-wrong-while-activating: %s", err)
1121 }
1122 onuLogger.WithFields(log.Fields{
1123 "OnuId": o.ID,
1124 "IntfId": o.PonPortID,
1125 "OnuSn": o.Sn(),
1126 "ActiveImageEntityId": o.ActiveImageEntityId,
1127 "CommittedImageEntityId": o.CommittedImageEntityId,
1128 }).Info("onu-software-image-activated")
1129
1130 // powercycle the ONU
1131 // we run this in a separate goroutine so that
1132 // the ActivateSoftwareResponse is sent to VOLTHA
1133 // NOTE do we need to wait before rebooting?
1134 go func() {
1135 if err := o.Reboot(10 * time.Second); err != nil {
1136 log.WithFields(log.Fields{
1137 "IntfId": o.PonPortID,
1138 "OnuId": o.ID,
1139 "SerialNumber": o.Sn(),
1140 "err": err,
1141 }).Error("cannot-reboot-onu-after-omci-activate-software-request")
1142 }
1143 }()
1144 }
1145 case omci.CommitSoftwareRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001146 if responsePkt, errResp = omcilib.CreateCommitSoftwareResponse(msg.OmciPkt, msg.OmciMsg); errResp == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001147 o.MibDataSync++
Matteo Scandolob5913142021-03-19 16:10:18 -07001148 if msgObj, err := omcilib.ParseCommitSoftwareRequest(msg.OmciPkt); err == nil {
Matteo Scandolocedde462021-03-09 17:37:16 -08001149 // TODO validate that the image to commit is:
1150 // - active
1151 // - not already committed
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001152 o.ActiveImageEntityId = msgObj.EntityInstance
Matteo Scandolocedde462021-03-09 17:37:16 -08001153 o.CommittedImageEntityId = msgObj.EntityInstance
Matteo Scandoloc00e97a2021-05-27 11:45:27 -07001154 //committed becomes standby
1155 o.StandbyImageVersion = o.CommittedImageVersion
1156 o.CommittedImageVersion = o.ActiveImageVersion
Matteo Scandolocedde462021-03-09 17:37:16 -08001157 } else {
1158 onuLogger.Errorf("something-went-wrong-while-committing: %s", err)
1159 }
1160 if err := o.InternalState.Event(OnuTxCommitImage); err != nil {
1161 onuLogger.WithFields(log.Fields{
1162 "OnuId": o.ID,
1163 "IntfId": o.PonPortID,
1164 "OnuSn": o.Sn(),
1165 "Err": err.Error(),
1166 }).Errorf("cannot-change-onu-internal-state-to-%s", OnuStateImageCommitted)
1167 }
1168 onuLogger.WithFields(log.Fields{
1169 "OnuId": o.ID,
1170 "IntfId": o.PonPortID,
1171 "OnuSn": o.Sn(),
1172 "ActiveImageEntityId": o.ActiveImageEntityId,
1173 "CommittedImageEntityId": o.CommittedImageEntityId,
1174 }).Info("onu-software-image-committed")
1175 }
Himani Chawla13b1ee02021-03-15 01:43:53 +05301176 case omci.GetAllAlarmsRequestType:
1177 // Reset the alarm sequence number on receiving get all alarms request.
1178 o.onuAlarmsInfoLock.Lock()
1179 for key, alarmInfo := range o.onuAlarmsInfo {
1180 // reset the alarm sequence no
1181 alarmInfo.SequenceNo = 0
1182 o.onuAlarmsInfo[key] = alarmInfo
1183 }
1184 o.onuAlarmsInfoLock.Unlock()
Matteo Scandolob5913142021-03-19 16:10:18 -07001185 responsePkt, _ = omcilib.CreateGetAllAlarmsResponse(msg.OmciMsg.TransactionID, o.onuAlarmsInfo)
Himani Chawla13b1ee02021-03-15 01:43:53 +05301186 case omci.GetAllAlarmsNextRequestType:
Matteo Scandolob5913142021-03-19 16:10:18 -07001187 if responsePkt, errResp = omcilib.CreateGetAllAlarmsNextResponse(msg.OmciPkt, msg.OmciMsg, o.onuAlarmsInfo); errResp != nil {
Himani Chawla13b1ee02021-03-15 01:43:53 +05301188 responsePkt = nil //Do not send any response for error case
1189 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001190 default:
Matteo Scandolocedde462021-03-09 17:37:16 -08001191 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001192 "omciBytes": hex.EncodeToString(msg.OmciPkt.Data()),
1193 "omciPkt": msg.OmciPkt,
1194 "omciMsgType": msg.OmciMsg.MessageType,
1195 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001196 "IntfId": o.PonPortID,
1197 "SerialNumber": o.Sn(),
1198 }).Warnf("OMCI-message-not-supported")
1199 }
1200
1201 if responsePkt != nil {
Matteo Scandolob5913142021-03-19 16:10:18 -07001202 if err := o.sendOmciIndication(responsePkt, msg.OmciMsg.TransactionID, stream); err != nil {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001203 onuLogger.WithFields(log.Fields{
Matteo Scandolob5913142021-03-19 16:10:18 -07001204 "IntfId": o.PonPortID,
1205 "SerialNumber": o.Sn(),
1206 "omciPacket": responsePkt,
1207 "msg.OmciMsgType": msg.OmciMsg.MessageType,
1208 "transCorrId": msg.OmciMsg.TransactionID,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001209 }).Errorf("failed-to-send-omci-message: %v", err)
1210 }
1211 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001212
Pragya Arya324337e2020-02-20 14:35:08 +05301213 o.publishOmciEvent(msg)
Andrea Campanellabe1b7cf2021-04-30 09:53:40 +02001214 return nil
Matteo Scandolof9d43412021-01-12 11:11:34 -08001215}
Pragya Arya324337e2020-02-20 14:35:08 +05301216
Matteo Scandolof9d43412021-01-12 11:11:34 -08001217// sendOmciIndication takes an OMCI packet and sends it up to VOLTHA
1218func (o *Onu) sendOmciIndication(responsePkt []byte, txId uint16, stream bbsim.Stream) error {
1219 indication := &openolt.Indication_OmciInd{
1220 OmciInd: &openolt.OmciIndication{
1221 IntfId: o.PonPortID,
1222 OnuId: o.ID,
1223 Pkt: responsePkt,
1224 },
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001225 }
Matteo Scandolof9d43412021-01-12 11:11:34 -08001226 if err := stream.Send(&openolt.Indication{Data: indication}); err != nil {
1227 return fmt.Errorf("failed-to-send-omci-message: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001228 }
1229 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001230 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -07001231 "SerialNumber": o.Sn(),
Matteo Scandolof9d43412021-01-12 11:11:34 -08001232 "omciPacket": indication.OmciInd.Pkt,
1233 "transCorrId": txId,
1234 }).Trace("omci-message-sent")
1235 return nil
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001236}
1237
Matteo Scandolo27428702019-10-11 16:21:16 -07001238func (o *Onu) storePortNumber(portNo uint32) {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001239 // NOTE this needed only as long as we don't support multiple UNIs
Matteo Scandolo27428702019-10-11 16:21:16 -07001240 // we need to add support for multiple UNIs
1241 // the action plan is:
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001242 // - refactor the omcisim-sim library to use https://github.com/cboling/omci instead of canned messages
Matteo Scandolo27428702019-10-11 16:21:16 -07001243 // - change the library so that it reports a single UNI and remove this workaroung
1244 // - add support for multiple UNIs in BBSim
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001245 if o.PortNo == 0 || portNo < o.PortNo {
Matteo Scandolo813402b2019-10-23 19:24:52 -07001246 onuLogger.WithFields(log.Fields{
1247 "IntfId": o.PonPortID,
1248 "OnuId": o.ID,
1249 "SerialNumber": o.Sn(),
1250 "OnuPortNo": o.PortNo,
1251 "FlowPortNo": portNo,
1252 }).Debug("Storing ONU portNo")
Matteo Scandolo27428702019-10-11 16:21:16 -07001253 o.PortNo = portNo
1254 }
1255}
1256
William Kurkian0418bc82019-11-06 12:16:24 -05001257func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -08001258 onuLogger.WithFields(log.Fields{
1259 "IntfId": o.PonPortID,
1260 "OnuId": id,
1261 "SerialNumber": o.Sn(),
1262 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -05001263 o.ID = id
1264}
1265
Matteo Scandolof9d43412021-01-12 11:11:34 -08001266func (o *Onu) handleFlowAdd(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001267 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001268 "AllocId": msg.Flow.AllocId,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001269 "Cookie": msg.Flow.Cookie,
1270 "DstPort": msg.Flow.Classifier.DstPort,
1271 "FlowId": msg.Flow.FlowId,
1272 "FlowType": msg.Flow.FlowType,
1273 "GemportId": msg.Flow.GemportId,
1274 "InnerVlan": msg.Flow.Classifier.IVid,
1275 "IntfId": msg.Flow.AccessIntfId,
1276 "IpProto": msg.Flow.Classifier.IpProto,
1277 "OnuId": msg.Flow.OnuId,
1278 "OnuSn": o.Sn(),
1279 "OuterVlan": msg.Flow.Classifier.OVid,
1280 "PortNo": msg.Flow.PortNo,
1281 "SrcPort": msg.Flow.Classifier.SrcPort,
1282 "UniID": msg.Flow.UniId,
1283 "ClassifierEthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
1284 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
1285 "ClassifierIVid": msg.Flow.Classifier.IVid,
1286 "ClassifierOVid": msg.Flow.Classifier.OVid,
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001287 "ReplicateFlow": msg.Flow.ReplicateFlow,
1288 "PbitToGemport": msg.Flow.PbitToGemport,
Matteo Scandoloedf30c72020-09-18 18:15:28 -07001289 }).Debug("OLT receives FlowAdd for ONU")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001290
Matteo Scandolo813402b2019-10-23 19:24:52 -07001291 if msg.Flow.UniId != 0 {
1292 // as of now BBSim only support a single UNI, so ignore everything that is not targeted to it
1293 onuLogger.WithFields(log.Fields{
1294 "IntfId": o.PonPortID,
1295 "OnuId": o.ID,
1296 "SerialNumber": o.Sn(),
1297 }).Debug("Ignoring flow as it's not for the first UNI")
1298 return
1299 }
1300
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001301 o.FlowIds = append(o.FlowIds, msg.Flow.FlowId)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001302
1303 var gemPortId uint32
1304 if msg.Flow.ReplicateFlow {
1305 // This means that the OLT should replicate the flow for each PBIT, for BBSim it's enough to use the
1306 // first available gemport (we only need to send one packet)
1307 // NOTE different TP may create different mapping between PBits and GemPorts, this may require some changes
1308 gemPortId = msg.Flow.PbitToGemport[0]
1309 } else {
1310 // if replicateFlows is false, then the flow is carrying the correct GemPortId
1311 gemPortId = uint32(msg.Flow.GemportId)
1312 }
1313 o.addGemPortToService(gemPortId, msg.Flow.Classifier.EthType, msg.Flow.Classifier.OVid, msg.Flow.Classifier.IVid)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001314
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001315 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo27428702019-10-11 16:21:16 -07001316 // NOTE storing the PortNO, it's needed when sending PacketIndications
Matteo Scandolo813402b2019-10-23 19:24:52 -07001317 o.storePortNumber(uint32(msg.Flow.PortNo))
Matteo Scandolo4a036262020-08-17 15:56:13 -07001318
1319 for _, s := range o.Services {
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001320 s.HandleAuth()
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001321 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001322 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
1323 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolobd875b32020-09-18 17:46:31 -07001324 msg.Flow.Classifier.DstPort == uint32(67) {
Matteo Scandolo99f18462019-10-28 14:14:28 -07001325
Matteo Scandolo4a036262020-08-17 15:56:13 -07001326 for _, s := range o.Services {
Matteo Scandolobd875b32020-09-18 17:46:31 -07001327 s.HandleDhcp(uint8(msg.Flow.Classifier.OPbits), int(msg.Flow.Classifier.OVid))
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001328 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001329 }
1330}
1331
Matteo Scandolof9d43412021-01-12 11:11:34 -08001332func (o *Onu) handleFlowRemove(msg bbsim.OnuFlowUpdateMessage) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001333 onuLogger.WithFields(log.Fields{
1334 "IntfId": o.PonPortID,
1335 "OnuId": o.ID,
1336 "SerialNumber": o.Sn(),
1337 "FlowId": msg.Flow.FlowId,
1338 "FlowType": msg.Flow.FlowType,
1339 }).Debug("ONU receives FlowRemove")
1340
1341 for idx, flow := range o.FlowIds {
1342 // If the gemport is found, delete it from local cache.
1343 if flow == msg.Flow.FlowId {
1344 o.FlowIds = append(o.FlowIds[:idx], o.FlowIds[idx+1:]...)
1345 break
1346 }
1347 }
1348
1349 if len(o.FlowIds) == 0 {
1350 onuLogger.WithFields(log.Fields{
1351 "IntfId": o.PonPortID,
1352 "OnuId": o.ID,
1353 "SerialNumber": o.Sn(),
1354 }).Info("Resetting GemPort")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001355
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301356 // check if ONU delete is performed and
1357 // terminate the ONU's ProcessOnuMessages Go routine
Matteo Scandolocedde462021-03-09 17:37:16 -08001358 if o.InternalState.Current() == OnuStateDisabled {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301359 close(o.Channel)
1360 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001361 }
1362}
1363
Matteo Scandolocedde462021-03-09 17:37:16 -08001364func (o *Onu) Reboot(timeout time.Duration) error {
1365 onuLogger.WithFields(log.Fields{
1366 "IntfId": o.PonPortID,
1367 "OnuId": o.ID,
1368 "SerialNumber": o.Sn(),
1369 }).Debug("shutting-down-onu")
1370 if err := o.HandleShutdownONU(); err != nil {
1371 return err
1372 }
1373 time.Sleep(timeout)
1374 onuLogger.WithFields(log.Fields{
1375 "IntfId": o.PonPortID,
1376 "OnuId": o.ID,
1377 "SerialNumber": o.Sn(),
1378 }).Debug("power-on-onu")
1379 if err := o.HandlePowerOnONU(); err != nil {
1380 return err
1381 }
1382 return nil
1383}
1384
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001385// BBR methods
1386
1387func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
1388 omciMsg := openolt.OmciMsg{
1389 IntfId: intfId,
1390 OnuId: onuId,
1391 Pkt: pktBytes,
1392 }
1393
1394 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
1395 log.WithFields(log.Fields{
1396 "IntfId": intfId,
1397 "OnuId": onuId,
1398 "SerialNumber": common.OnuSnToString(sn),
1399 "Pkt": omciMsg.Pkt,
1400 }).Fatalf("Failed to send MIB Reset")
1401 }
1402 log.WithFields(log.Fields{
1403 "IntfId": intfId,
1404 "OnuId": onuId,
1405 "SerialNumber": common.OnuSnToString(sn),
1406 "Pkt": omciMsg.Pkt,
1407 }).Tracef("Sent OMCI message %s", msgType)
1408}
1409
1410func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
1411 var next uint16
1412 if len(highPriority) > 0 && highPriority[0] {
1413 next = onu.hpTid
1414 onu.hpTid += 1
1415 if onu.hpTid < 0x8000 {
1416 onu.hpTid = 0x8000
1417 }
1418 } else {
1419 next = onu.tid
1420 onu.tid += 1
1421 if onu.tid >= 0x8000 {
1422 onu.tid = 1
1423 }
1424 }
1425 return next
1426}
1427
1428// TODO move this method in responders/omcisim
1429func (o *Onu) StartOmci(client openolt.OpenoltClient) {
1430 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
1431 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
1432}
1433
Matteo Scandolof9d43412021-01-12 11:11:34 -08001434// handleOmciResponse is used in BBR to generate the OMCI packets the openolt-adapter would send to the device
1435func (o *Onu) handleOmciResponse(msg bbsim.OmciIndicationMessage, client openolt.OpenoltClient) {
1436
1437 // we need to encode the packet in HEX
1438 pkt := make([]byte, len(msg.OmciInd.Pkt)*2)
1439 hex.Encode(pkt, msg.OmciInd.Pkt)
1440 packet, omciMsg, err := omcilib.ParseOpenOltOmciPacket(pkt)
1441 if err != nil {
1442 log.WithFields(log.Fields{
1443 "IntfId": o.PonPortID,
1444 "SerialNumber": o.Sn(),
1445 "omciPacket": msg.OmciInd.Pkt,
1446 }).Error("BBR Cannot parse OMCI packet")
1447 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001448
1449 log.WithFields(log.Fields{
1450 "IntfId": msg.OmciInd.IntfId,
1451 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001452 "OnuSn": o.Sn(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001453 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001454 "msgType": omciMsg.MessageType,
Anand S Katti09541352020-01-29 15:54:01 +05301455 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolof9d43412021-01-12 11:11:34 -08001456 switch omciMsg.MessageType {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001457 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -07001458 log.WithFields(log.Fields{
1459 "IntfId": msg.OmciInd.IntfId,
1460 "OnuId": msg.OmciInd.OnuId,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001461 "OnuSn": o.Sn(),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001462 "Pkt": msg.OmciInd.Pkt,
Matteo Scandolof9d43412021-01-12 11:11:34 -08001463 "msgType": omciMsg.MessageType,
Matteo Scandolo813402b2019-10-23 19:24:52 -07001464 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001465 case omci.MibResetResponseType:
1466 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
1467 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
1468 case omci.MibUploadResponseType:
1469 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1470 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
1471 case omci.MibUploadNextResponseType:
1472 o.seqNumber++
1473
1474 if o.seqNumber > 290 {
1475 // 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 -08001476 // 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 -08001477 if err := o.InternalState.Event(BbrOnuTxSendEapolFlow); err != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001478 onuLogger.WithFields(log.Fields{
1479 "OnuId": o.ID,
1480 "IntfId": o.PonPortID,
1481 "OnuSn": o.Sn(),
1482 }).Errorf("Error while transitioning ONU State %v", err)
1483 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001484 } else {
1485 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
1486 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001487 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001488 }
1489}
1490
1491func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
1492
1493 classifierProto := openolt.Classifier{
1494 EthType: uint32(layers.EthernetTypeEAPOL),
1495 OVid: 4091,
1496 }
1497
1498 actionProto := openolt.Action{}
1499
1500 downstreamFlow := openolt.Flow{
1501 AccessIntfId: int32(o.PonPortID),
1502 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001503 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001504 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001505 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001506 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001507 Classifier: &classifierProto,
1508 Action: &actionProto,
1509 Priority: int32(100),
1510 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001511 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1512 // AllocId and GemPorts need to be unique per PON
1513 // for now use the ONU-ID, will need to change once we support multiple UNIs
1514 AllocId: int32(o.ID),
1515 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001516 }
1517
1518 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1519 log.WithFields(log.Fields{
1520 "IntfId": o.PonPortID,
1521 "OnuId": o.ID,
1522 "FlowId": downstreamFlow.FlowId,
1523 "PortNo": downstreamFlow.PortNo,
1524 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001525 "Err": err,
Matteo Scandolob0e3e622020-04-23 17:00:29 -07001526 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001527 }
1528 log.WithFields(log.Fields{
1529 "IntfId": o.PonPortID,
1530 "OnuId": o.ID,
1531 "FlowId": downstreamFlow.FlowId,
1532 "PortNo": downstreamFlow.PortNo,
1533 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1534 }).Info("Sent EAPOL Flow")
1535}
1536
1537func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
Matteo Scandolo4a036262020-08-17 15:56:13 -07001538
1539 // BBR only works with a single service (ATT HSIA)
1540 hsia := o.Services[0].(*Service)
1541
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001542 classifierProto := openolt.Classifier{
1543 EthType: uint32(layers.EthernetTypeIPv4),
1544 SrcPort: uint32(68),
1545 DstPort: uint32(67),
Matteo Scandolo4a036262020-08-17 15:56:13 -07001546 OVid: uint32(hsia.CTag),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001547 }
1548
1549 actionProto := openolt.Action{}
1550
1551 downstreamFlow := openolt.Flow{
1552 AccessIntfId: int32(o.PonPortID),
1553 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001554 UniId: int32(0), // FIXME do not hardcode this
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001555 FlowId: uint64(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001556 FlowType: "downstream",
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001557 NetworkIntfId: int32(0),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001558 Classifier: &classifierProto,
1559 Action: &actionProto,
1560 Priority: int32(100),
1561 Cookie: uint64(o.ID),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001562 PortNo: o.ID, // NOTE we are using this to map an incoming packetIndication to an ONU
1563 // AllocId and GemPorts need to be unique per PON
1564 // for now use the ONU-ID, will need to change once we support multiple UNIs
1565 AllocId: int32(o.ID),
1566 GemportId: int32(o.ID),
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001567 }
1568
1569 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1570 log.WithFields(log.Fields{
1571 "IntfId": o.PonPortID,
1572 "OnuId": o.ID,
1573 "FlowId": downstreamFlow.FlowId,
1574 "PortNo": downstreamFlow.PortNo,
1575 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001576 "Err": err,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001577 }).Fatalf("Failed to send DHCP Flow")
1578 }
1579 log.WithFields(log.Fields{
1580 "IntfId": o.PonPortID,
1581 "OnuId": o.ID,
1582 "FlowId": downstreamFlow.FlowId,
1583 "PortNo": downstreamFlow.PortNo,
1584 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1585 }).Info("Sent DHCP Flow")
1586}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301587
1588// DeleteFlow method search and delete flowKey from the onu flows slice
1589func (onu *Onu) DeleteFlow(key FlowKey) {
1590 for pos, flowKey := range onu.Flows {
1591 if flowKey == key {
1592 // delete the flowKey by shifting all flowKeys by one
1593 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1594 t := make([]FlowKey, len(onu.Flows))
1595 copy(t, onu.Flows)
1596 onu.Flows = t
1597 break
1598 }
1599 }
1600}
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301601
1602func (onu *Onu) ReDiscoverOnu() {
1603 // Wait for few seconds to be sure of the cleanup
1604 time.Sleep(5 * time.Second)
1605
1606 onuLogger.WithFields(log.Fields{
1607 "IntfId": onu.PonPortID,
1608 "OnuId": onu.ID,
1609 "OnuSn": onu.Sn(),
1610 }).Debug("Send ONU Re-Discovery")
1611
1612 // ONU Re-Discovery
Matteo Scandolocedde462021-03-09 17:37:16 -08001613 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301614 log.WithFields(log.Fields{
1615 "IntfId": onu.PonPortID,
1616 "OnuSn": onu.Sn(),
1617 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001618 }).Infof("Failed to transition ONU to %s state: %s", OnuStateInitialized, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301619 }
1620
Matteo Scandolocedde462021-03-09 17:37:16 -08001621 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301622 log.WithFields(log.Fields{
1623 "IntfId": onu.PonPortID,
1624 "OnuSn": onu.Sn(),
1625 "OnuId": onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -08001626 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDiscovered, err.Error())
Hardik Windlass7b3405b2020-07-08 15:10:05 +05301627 }
1628}
Matteo Scandolo4a036262020-08-17 15:56:13 -07001629
1630func (onu *Onu) addGemPortToService(gemport uint32, ethType uint32, oVlan uint32, iVlan uint32) {
1631 for _, s := range onu.Services {
1632 if service, ok := s.(*Service); ok {
1633 // EAPOL is a strange case, as packets are untagged
1634 // but we assume we will have a single service requiring EAPOL
1635 if ethType == uint32(layers.EthernetTypeEAPOL) && service.NeedsEapol {
1636 service.GemPort = gemport
1637 }
1638
1639 // For DHCP services we single tag the outgoing packets,
1640 // thus the flow only contains the CTag and we can use that to match the service
1641 if ethType == uint32(layers.EthernetTypeIPv4) && service.NeedsDhcp && service.CTag == int(oVlan) {
1642 service.GemPort = gemport
1643 }
1644
1645 // for dataplane services match both C and S tags
1646 if service.CTag == int(iVlan) && service.STag == int(oVlan) {
1647 service.GemPort = gemport
1648 }
1649 }
1650 }
1651}
1652
1653func (onu *Onu) findServiceByMacAddress(macAddress net.HardwareAddr) (*Service, error) {
1654 for _, s := range onu.Services {
1655 service := s.(*Service)
1656 if service.HwAddress.String() == macAddress.String() {
1657 return service, nil
1658 }
1659 }
1660 return nil, fmt.Errorf("cannot-find-service-with-mac-address-%s", macAddress.String())
1661}
Himani Chawla13b1ee02021-03-15 01:43:53 +05301662
1663func (o *Onu) SendOMCIAlarmNotificationMsg(raiseOMCIAlarm bool, alarmType string) {
1664 switch alarmType {
1665 case "ONU_ALARM_LOS":
1666 msg := bbsim.Message{
1667 Type: bbsim.UniStatusAlarm,
1668 Data: bbsim.UniStatusAlarmMessage{
1669 OnuSN: o.SerialNumber,
1670 OnuID: o.ID,
1671 EntityID: 257,
1672 RaiseOMCIAlarm: raiseOMCIAlarm,
1673 },
1674 }
1675 o.Channel <- msg
1676 }
1677
1678}
1679
1680func (o *Onu) IncrementAlarmSequenceNumber(key omcilib.OnuAlarmInfoMapKey) uint8 {
1681 o.onuAlarmsInfoLock.Lock()
1682 defer o.onuAlarmsInfoLock.Unlock()
1683 if alarmInfo, ok := o.onuAlarmsInfo[key]; ok {
1684 if alarmInfo.SequenceNo == 255 {
1685 alarmInfo.SequenceNo = 1
1686 } else {
1687 alarmInfo.SequenceNo++
1688 }
1689 o.onuAlarmsInfo[key] = alarmInfo
1690 return alarmInfo.SequenceNo
1691 } else {
1692 // This is the first time alarm notification message is being sent
1693 o.onuAlarmsInfo[key] = omcilib.OnuAlarmInfo{
1694 SequenceNo: 1,
1695 }
1696 return 1
1697 }
1698}