blob: 068a250e5b24ce5f1e76fa0cc9a97fb238cdbfff [file] [log] [blame]
Matteo Scandolo86e8ce62019-10-11 12:03:10 -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
17package devices
18
19import (
20 "bytes"
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070021 "fmt"
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080022 "sync"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020023
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070024 "github.com/looplab/fsm"
Elia Battistonb7bea222022-02-18 16:25:00 +010025 "github.com/opencord/bbsim/internal/common"
David K. Bainbridgec415efe2021-08-19 13:05:21 +000026 "github.com/opencord/voltha-protos/v5/go/openolt"
Pragya Arya6a708d62020-01-01 17:17:20 +053027 log "github.com/sirupsen/logrus"
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070028)
29
Matteo Scandolod15c0b42021-03-22 11:38:13 -070030var ponLogger = log.WithFields(log.Fields{
31 "module": "PON",
32})
33
Girish Gowdra574834a2022-02-04 15:15:15 -080034type AllocIDVal struct {
35 OnuSn *openolt.SerialNumber
36 AllocID uint16
37}
38
39type AllocIDKey struct {
40 PonID uint32
41 OnuID uint32
42 EntityID uint16
43}
44
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070045type PonPort struct {
46 // BBSIM Internals
Pragya Arya996a0892020-03-09 21:47:52 +053047 ID uint32
Elia Battistonb7bea222022-02-18 16:25:00 +010048 Technology common.PonTechnology
Pragya Arya996a0892020-03-09 21:47:52 +053049 NumOnu int
50 Onus []*Onu
51 Olt *OltDevice
52 PacketCount uint64
53 InternalState *fsm.FSM
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070054
55 // PON Attributes
56 OperState *fsm.FSM
57 Type string
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080058
59 // Allocated resources
60 // Some resources (eg: OnuId, AllocId and GemPorts) have to be unique per PON port
61 // we are keeping a list so that we can throw an error in cases we receive duplicates
62 AllocatedGemPorts map[uint16]*openolt.SerialNumber
63 allocatedGemPortsLock sync.RWMutex
64 AllocatedOnuIds map[uint32]*openolt.SerialNumber
65 allocatedOnuIdsLock sync.RWMutex
Girish Gowdra574834a2022-02-04 15:15:15 -080066 AllocatedAllocIds map[AllocIDKey]*AllocIDVal // key is AllocIDKey
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080067 allocatedAllocIdsLock sync.RWMutex
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070068}
69
Pragya Arya6a708d62020-01-01 17:17:20 +053070// CreatePonPort creates pon port object
Elia Battistonb7bea222022-02-18 16:25:00 +010071func CreatePonPort(olt *OltDevice, id uint32, tech common.PonTechnology) *PonPort {
Pragya Arya6a708d62020-01-01 17:17:20 +053072 ponPort := PonPort{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080073 NumOnu: olt.NumOnuPerPon,
74 ID: id,
Elia Battistonb7bea222022-02-18 16:25:00 +010075 Technology: tech,
Matteo Scandolo4b077aa2021-02-16 17:33:37 -080076 Type: "pon",
77 Olt: olt,
78 Onus: []*Onu{},
79 AllocatedGemPorts: make(map[uint16]*openolt.SerialNumber),
80 AllocatedOnuIds: make(map[uint32]*openolt.SerialNumber),
Girish Gowdra574834a2022-02-04 15:15:15 -080081 AllocatedAllocIds: make(map[AllocIDKey]*AllocIDVal),
Pragya Arya6a708d62020-01-01 17:17:20 +053082 }
83
Pragya Arya2225f202020-01-29 18:05:01 +053084 ponPort.InternalState = fsm.NewFSM(
85 "created",
86 fsm.Events{
87 {Name: "enable", Src: []string{"created", "disabled"}, Dst: "enabled"},
88 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
89 },
90 fsm.Callbacks{
91 "enter_enabled": func(e *fsm.Event) {
Matteo Scandolod15c0b42021-03-22 11:38:13 -070092 ponLogger.WithFields(log.Fields{
Pragya Arya2225f202020-01-29 18:05:01 +053093 "ID": ponPort.ID,
94 }).Debugf("Changing PON Port InternalState from %s to %s", e.Src, e.Dst)
95
96 if e.Src == "created" {
97 if olt.ControlledActivation == Default || olt.ControlledActivation == OnlyPON {
98 for _, onu := range ponPort.Onus {
Matteo Scandolocedde462021-03-09 17:37:16 -080099 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700100 ponLogger.Errorf("Error initializing ONU: %v", err)
Pragya Arya2225f202020-01-29 18:05:01 +0530101 continue
102 }
Matteo Scandolocedde462021-03-09 17:37:16 -0800103 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700104 ponLogger.Errorf("Error discover ONU: %v", err)
Pragya Arya2225f202020-01-29 18:05:01 +0530105 }
106 }
107 }
108 } else if e.Src == "disabled" {
Matteo Scandolo0de43d12020-10-05 13:54:41 -0700109 if ponPort.Olt.ControlledActivation == OnlyONU || ponPort.Olt.ControlledActivation == Both {
110 // if ONUs are manually activated then only initialize them
111 for _, onu := range ponPort.Onus {
Matteo Scandolocedde462021-03-09 17:37:16 -0800112 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700113 ponLogger.WithFields(log.Fields{
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800114 "Err": err,
115 "OnuSn": onu.Sn(),
Hardik Windlassad790cb2020-06-17 21:26:22 +0530116 "IntfId": onu.PonPortID,
117 }).Error("Error initializing ONU")
Pragya Arya2225f202020-01-29 18:05:01 +0530118 continue
119 }
Matteo Scandolo0de43d12020-10-05 13:54:41 -0700120 }
121 } else {
122 for _, onu := range ponPort.Onus {
Matteo Scandolocedde462021-03-09 17:37:16 -0800123 if onu.InternalState.Current() == OnuStatePonDisabled {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700124 if err := onu.InternalState.Event(OnuTxEnable); err != nil {
125 ponLogger.WithFields(log.Fields{
Matteo Scandolo0de43d12020-10-05 13:54:41 -0700126 "Err": err,
127 "OnuSn": onu.Sn(),
128 "IntfId": onu.PonPortID,
129 }).Error("Error enabling ONU")
130 }
Matteo Scandolocedde462021-03-09 17:37:16 -0800131 } else if onu.InternalState.Current() == OnuStateDisabled {
132 if err := onu.InternalState.Event(OnuTxInitialize); err != nil {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700133 ponLogger.WithFields(log.Fields{
Matteo Scandolo0de43d12020-10-05 13:54:41 -0700134 "Err": err,
135 "OnuSn": onu.Sn(),
136 "IntfId": onu.PonPortID,
137 }).Error("Error initializing ONU")
138 continue
139 }
Matteo Scandolocedde462021-03-09 17:37:16 -0800140 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700141 ponLogger.WithFields(log.Fields{
Matteo Scandolo0de43d12020-10-05 13:54:41 -0700142 "Err": err,
143 "OnuSn": onu.Sn(),
144 "IntfId": onu.PonPortID,
145 }).Error("Error discovering ONU")
146 }
Matteo Scandolocedde462021-03-09 17:37:16 -0800147 } else if onu.InternalState.Current() == OnuStateInitialized {
148 if err := onu.InternalState.Event(OnuTxDiscover); err != nil {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700149 ponLogger.WithFields(log.Fields{
Matteo Scandolo0de43d12020-10-05 13:54:41 -0700150 "Err": err,
151 "OnuSn": onu.Sn(),
152 "IntfId": onu.PonPortID,
153 }).Error("Error discovering ONU")
154 }
155 } else {
156 // this is to loudly report unexpected states in order to address them
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700157 ponLogger.WithFields(log.Fields{
Matteo Scandolo0de43d12020-10-05 13:54:41 -0700158 "OnuSn": onu.Sn(),
159 "IntfId": onu.PonPortID,
160 "InternalState": onu.InternalState.Current(),
161 }).Error("Unexpected ONU state in PON enabling")
Pragya Arya2225f202020-01-29 18:05:01 +0530162 }
163 }
164 }
165 }
166 },
167 "enter_disabled": func(e *fsm.Event) {
168 for _, onu := range ponPort.Onus {
Matteo Scandolocedde462021-03-09 17:37:16 -0800169 if onu.InternalState.Current() == OnuStateInitialized || onu.InternalState.Current() == OnuStateDisabled {
Pragya Arya2225f202020-01-29 18:05:01 +0530170 continue
171 }
Matteo Scandolocedde462021-03-09 17:37:16 -0800172 if err := onu.InternalState.Event(OnuTxPonDisable); err != nil {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700173 ponLogger.Errorf("Failed to move ONU in %s states: %v", OnuStatePonDisabled, err)
Pragya Arya2225f202020-01-29 18:05:01 +0530174 }
175 }
176 },
177 },
178 )
179
Pragya Arya6a708d62020-01-01 17:17:20 +0530180 ponPort.OperState = fsm.NewFSM(
181 "down",
182 fsm.Events{
183 {Name: "enable", Src: []string{"down"}, Dst: "up"},
184 {Name: "disable", Src: []string{"up"}, Dst: "down"},
185 },
186 fsm.Callbacks{
187 "enter_up": func(e *fsm.Event) {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700188 ponLogger.WithFields(log.Fields{
Pragya Arya6a708d62020-01-01 17:17:20 +0530189 "ID": ponPort.ID,
190 }).Debugf("Changing PON Port OperState from %s to %s", e.Src, e.Dst)
Pragya Arya2225f202020-01-29 18:05:01 +0530191 olt.sendPonIndication(ponPort.ID)
Pragya Arya6a708d62020-01-01 17:17:20 +0530192 },
193 "enter_down": func(e *fsm.Event) {
Matteo Scandolod15c0b42021-03-22 11:38:13 -0700194 ponLogger.WithFields(log.Fields{
Pragya Arya6a708d62020-01-01 17:17:20 +0530195 "ID": ponPort.ID,
196 }).Debugf("Changing PON Port OperState from %s to %s", e.Src, e.Dst)
Pragya Arya2225f202020-01-29 18:05:01 +0530197 olt.sendPonIndication(ponPort.ID)
Pragya Arya6a708d62020-01-01 17:17:20 +0530198 },
199 },
200 )
201 return &ponPort
202}
203
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800204func (p *PonPort) GetOnuBySn(sn *openolt.SerialNumber) (*Onu, error) {
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700205 for _, onu := range p.Onus {
206 if bytes.Equal(onu.SerialNumber.VendorSpecific, sn.VendorSpecific) {
Matteo Scandolo27428702019-10-11 16:21:16 -0700207 return onu, nil
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700208 }
209 }
Shrey Baid688b4242020-07-10 20:40:10 +0530210 return nil, fmt.Errorf("Cannot find Onu with serial number %d in PonPort %d", sn, p.ID)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700211}
212
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800213func (p *PonPort) GetOnuById(id uint32) (*Onu, error) {
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700214 for _, onu := range p.Onus {
215 if onu.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700216 return onu, nil
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700217 }
218 }
Shrey Baid688b4242020-07-10 20:40:10 +0530219 return nil, fmt.Errorf("Cannot find Onu with id %d in PonPort %d", id, p.ID)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700220}
Pragya Arya996a0892020-03-09 21:47:52 +0530221
222// GetNumOfActiveOnus returns number of active ONUs for PON port
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800223func (p *PonPort) GetNumOfActiveOnus() uint32 {
Pragya Arya996a0892020-03-09 21:47:52 +0530224 var count uint32 = 0
225 for _, onu := range p.Onus {
Matteo Scandolocedde462021-03-09 17:37:16 -0800226 if onu.InternalState.Current() == OnuStateInitialized || onu.InternalState.Current() == OnuStateCreated || onu.InternalState.Current() == OnuStateDisabled {
Pragya Arya996a0892020-03-09 21:47:52 +0530227 continue
228 }
229 count++
230 }
231 return count
232}
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800233
234// storeOnuId adds the Id to the ONU Ids already allocated to this PON port
235func (p *PonPort) storeOnuId(onuId uint32, onuSn *openolt.SerialNumber) {
236 p.allocatedOnuIdsLock.Lock()
237 defer p.allocatedOnuIdsLock.Unlock()
238 p.AllocatedOnuIds[onuId] = onuSn
239}
240
241// removeOnuId removes the OnuId from the allocated resources
242func (p *PonPort) removeOnuId(onuId uint32) {
243 p.allocatedOnuIdsLock.Lock()
244 defer p.allocatedOnuIdsLock.Unlock()
245 delete(p.AllocatedOnuIds, onuId)
246}
247
248func (p *PonPort) removeAllOnuIds() {
249 p.allocatedOnuIdsLock.Lock()
250 defer p.allocatedOnuIdsLock.Unlock()
251 p.AllocatedOnuIds = make(map[uint32]*openolt.SerialNumber)
252}
253
254// isOnuIdAllocated returns whether this OnuId is already in use on this PON
255func (p *PonPort) isOnuIdAllocated(onuId uint32) (bool, *openolt.SerialNumber) {
256 p.allocatedOnuIdsLock.RLock()
257 defer p.allocatedOnuIdsLock.RUnlock()
258
259 if _, ok := p.AllocatedOnuIds[onuId]; ok {
260 return true, p.AllocatedOnuIds[onuId]
261 }
262 return false, nil
263}
264
265// storeGemPort adds the gemPortId to the gemports already allocated to this PON port
266func (p *PonPort) storeGemPort(gemPortId uint16, onuSn *openolt.SerialNumber) {
267 p.allocatedGemPortsLock.Lock()
268 defer p.allocatedGemPortsLock.Unlock()
269 p.AllocatedGemPorts[gemPortId] = onuSn
270}
271
272// removeGemPort removes the gemPortId from the allocated resources
273func (p *PonPort) removeGemPort(gemPortId uint16) {
274 p.allocatedGemPortsLock.Lock()
275 defer p.allocatedGemPortsLock.Unlock()
276 delete(p.AllocatedGemPorts, gemPortId)
277}
278
279func (p *PonPort) removeGemPortBySn(onuSn *openolt.SerialNumber) {
280 p.allocatedGemPortsLock.Lock()
281 defer p.allocatedGemPortsLock.Unlock()
282 for gemPort, sn := range p.AllocatedGemPorts {
283 if sn == onuSn {
284 delete(p.AllocatedGemPorts, gemPort)
285 }
286 }
287}
288
289func (p *PonPort) removeAllGemPorts() {
290 p.allocatedGemPortsLock.Lock()
291 defer p.allocatedGemPortsLock.Unlock()
292 p.AllocatedGemPorts = make(map[uint16]*openolt.SerialNumber)
293}
294
295// isGemPortAllocated returns whether this gemPort is already in use on this PON
296func (p *PonPort) isGemPortAllocated(gemPortId uint16) (bool, *openolt.SerialNumber) {
297 p.allocatedGemPortsLock.RLock()
298 defer p.allocatedGemPortsLock.RUnlock()
299
300 if _, ok := p.AllocatedGemPorts[gemPortId]; ok {
301 return true, p.AllocatedGemPorts[gemPortId]
302 }
303 return false, nil
304}
305
306// storeAllocId adds the Id to the ONU Ids already allocated to this PON port
Girish Gowdra574834a2022-02-04 15:15:15 -0800307func (p *PonPort) storeAllocId(ponID uint32, onuID uint32, entityID uint16, allocId uint16, onuSn *openolt.SerialNumber) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800308 p.allocatedAllocIdsLock.Lock()
309 defer p.allocatedAllocIdsLock.Unlock()
Girish Gowdra574834a2022-02-04 15:15:15 -0800310 p.AllocatedAllocIds[AllocIDKey{ponID, onuID, entityID}] = &AllocIDVal{onuSn, allocId}
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800311}
312
313// removeAllocId removes the AllocId from the allocated resources
Girish Gowdra574834a2022-02-04 15:15:15 -0800314func (p *PonPort) removeAllocId(ponID uint32, onuID uint32, entityID uint16) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800315 p.allocatedAllocIdsLock.Lock()
316 defer p.allocatedAllocIdsLock.Unlock()
Girish Gowdra574834a2022-02-04 15:15:15 -0800317 allocKey := AllocIDKey{ponID, onuID, entityID}
318 delete(p.AllocatedAllocIds, allocKey)
319}
320
321// removeAllocIdsForOnuSn removes the all AllocIds for the given onu serial number
322func (p *PonPort) removeAllocIdsForOnuSn(onuSn *openolt.SerialNumber) {
323 p.allocatedAllocIdsLock.Lock()
324 defer p.allocatedAllocIdsLock.Unlock()
325 for id, allocObj := range p.AllocatedAllocIds {
326 if onuSn == allocObj.OnuSn {
327 delete(p.AllocatedAllocIds, id)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800328 }
329 }
330}
331
332func (p *PonPort) removeAllAllocIds() {
333 p.allocatedAllocIdsLock.Lock()
334 defer p.allocatedAllocIdsLock.Unlock()
Girish Gowdra574834a2022-02-04 15:15:15 -0800335 p.AllocatedAllocIds = make(map[AllocIDKey]*AllocIDVal)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800336}
337
338// isAllocIdAllocated returns whether this AllocId is already in use on this PON
Girish Gowdra574834a2022-02-04 15:15:15 -0800339func (p *PonPort) isAllocIdAllocated(ponID uint32, onuID uint32, entityID uint16) (bool, *AllocIDVal) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800340 p.allocatedAllocIdsLock.RLock()
341 defer p.allocatedAllocIdsLock.RUnlock()
Girish Gowdra574834a2022-02-04 15:15:15 -0800342 allocKey := AllocIDKey{ponID, onuID, entityID}
343 if _, ok := p.AllocatedAllocIds[allocKey]; ok {
344 return true, p.AllocatedAllocIds[allocKey]
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800345 }
346 return false, nil
347}