blob: 9b99c7965a4767c8635944b1db79890c826129ee [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 (
20 "context"
Matteo Scandolo4a036262020-08-17 15:56:13 -070021 "encoding/hex"
Matteo Scandolo4747d292019-08-05 11:50:18 -070022 "fmt"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020023 "net"
Matteo Scandolof9d43412021-01-12 11:11:34 -080024 "strconv"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020025 "sync"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010026 "time"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020027
Elia Battistonac63b112022-01-12 18:40:49 +010028 "github.com/opencord/voltha-protos/v5/go/extension"
29
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000030 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
31 "github.com/opencord/bbsim/internal/bbsim/types"
32 omcilib "github.com/opencord/bbsim/internal/common/omci"
David K. Bainbridgec415efe2021-08-19 13:05:21 +000033 "github.com/opencord/voltha-protos/v5/go/ext/config"
Holger Hildebrandtc10bab12021-04-27 09:23:48 +000034
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070035 "github.com/google/gopacket"
36 "github.com/google/gopacket/layers"
Matteo Scandolo4747d292019-08-05 11:50:18 -070037 "github.com/looplab/fsm"
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070038 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +010039 "github.com/opencord/bbsim/internal/common"
David K. Bainbridgec415efe2021-08-19 13:05:21 +000040 "github.com/opencord/voltha-protos/v5/go/openolt"
41 "github.com/opencord/voltha-protos/v5/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070042 log "github.com/sirupsen/logrus"
43 "google.golang.org/grpc"
Pragya Arya8bdb4532020-03-02 17:08:09 +053044 "google.golang.org/grpc/codes"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010045 "google.golang.org/grpc/reflection"
Pragya Arya8bdb4532020-03-02 17:08:09 +053046 "google.golang.org/grpc/status"
Matteo Scandolo4747d292019-08-05 11:50:18 -070047)
48
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070049var oltLogger = log.WithFields(log.Fields{
Matteo Scandolo84f7d482019-08-08 19:00:47 -070050 "module": "OLT",
51})
52
Matteo Scandolocedde462021-03-09 17:37:16 -080053const (
Elia Battiston67e9e4c2022-02-15 16:38:40 +010054 //InternalState FSM states and transitions
55 OltInternalStateCreated = "created"
56 OltInternalStateInitialized = "initialized"
57 OltInternalStateEnabled = "enabled"
58 OltInternalStateDisabled = "disabled"
59 OltInternalStateDeleted = "deleted"
60
61 OltInternalTxInitialize = "initialize"
62 OltInternalTxEnable = "enable"
63 OltInternalTxDisable = "disable"
64 OltInternalTxDelete = "delete"
Matteo Scandolocedde462021-03-09 17:37:16 -080065)
66
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070067type OltDevice struct {
David Bainbridge103cf022019-12-16 20:11:35 +000068 sync.Mutex
Hardik Windlassefdb4b62021-03-18 10:33:24 +000069 OltServer *grpc.Server
David Bainbridge103cf022019-12-16 20:11:35 +000070
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070071 // BBSIM Internals
Pragya Arya2225f202020-01-29 18:05:01 +053072 ID int
73 SerialNumber string
74 NumNni int
Elia Battiston420c9092022-02-02 12:17:54 +010075 NniSpeed uint32
Pragya Arya2225f202020-01-29 18:05:01 +053076 NumPon int
77 NumOnuPerPon int
Mahir Gunyela1753ae2021-06-23 00:24:56 -070078 NumUni int
Elia Battistonac63b112022-01-12 18:40:49 +010079 NumPots int
Pragya Arya2225f202020-01-29 18:05:01 +053080 InternalState *fsm.FSM
Matteo Scandolof9d43412021-01-12 11:11:34 -080081 channel chan types.Message
Matteo Scandolo90d08f62020-10-29 12:06:55 -070082 dhcpServer dhcp.DHCPServerIf
Andrea Campanellabe8e12f2020-12-14 18:43:41 +010083 Flows sync.Map
Pragya Arya2225f202020-01-29 18:05:01 +053084 Delay int
85 ControlledActivation mode
Pragya Arya324337e2020-02-20 14:35:08 +053086 EventChannel chan common.Event
87 PublishEvents bool
Pragya Arya996a0892020-03-09 21:47:52 +053088 PortStatsInterval int
Matteo Scandolo96f89192021-03-12 13:17:26 -080089 PreviouslyConnected bool
Matteo Scandoloe33447a2019-10-31 12:38:23 -070090
Matteo Scandolo27428702019-10-11 16:21:16 -070091 Pons []*PonPort
92 Nnis []*NniPort
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070093
94 // OLT Attributes
95 OperState *fsm.FSM
David Bainbridge103cf022019-12-16 20:11:35 +000096
97 enableContext context.Context
98 enableContextCancel context.CancelFunc
Pragya Arya1cbefa42020-01-13 12:15:29 +053099
Matteo Scandolo4a036262020-08-17 15:56:13 -0700100 OpenoltStream openolt.Openolt_EnableIndicationServer
Anand S Katti09541352020-01-29 15:54:01 +0530101 enablePerf bool
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800102
103 // Allocated Resources
104 // this data are to verify that the openolt adapter does not duplicate resources
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000105 AllocIDsLock sync.RWMutex
106 AllocIDs map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool // map[ponPortId]map[OnuId]map[PortNo]map[AllocIds]map[FlowId]bool
107 GemPortIDsLock sync.RWMutex
108 GemPortIDs map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool // map[ponPortId]map[OnuId]map[PortNo]map[GemPortIDs]map[FlowId]bool
109 OmciResponseRate uint8
Matteo Scandolo4747d292019-08-05 11:50:18 -0700110}
111
Matteo Scandolo27428702019-10-11 16:21:16 -0700112var olt OltDevice
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700113
Matteo Scandolo27428702019-10-11 16:21:16 -0700114func GetOLT() *OltDevice {
115 return &olt
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700116}
117
Matteo Scandolo4a036262020-08-17 15:56:13 -0700118func CreateOLT(options common.GlobalConfig, services []common.ServiceYaml, isMock bool) *OltDevice {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700119 oltLogger.WithFields(log.Fields{
Pragya Arya996a0892020-03-09 21:47:52 +0530120 "ID": options.Olt.ID,
121 "NumNni": options.Olt.NniPorts,
Elia Battiston420c9092022-02-02 12:17:54 +0100122 "NniSpeed": options.Olt.NniSpeed,
Pragya Arya996a0892020-03-09 21:47:52 +0530123 "NumPon": options.Olt.PonPorts,
124 "NumOnuPerPon": options.Olt.OnusPonPort,
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700125 "NumUni": options.Olt.UniPorts,
Elia Battistonac63b112022-01-12 18:40:49 +0100126 "NumPots": options.Olt.PotsPorts,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700127 }).Debug("CreateOLT")
128
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700129 olt = OltDevice{
Pragya Arya996a0892020-03-09 21:47:52 +0530130 ID: options.Olt.ID,
131 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", options.Olt.ID),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700132 OperState: getOperStateFSM(func(e *fsm.Event) {
133 oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
134 }),
Matteo Scandolo96f89192021-03-12 13:17:26 -0800135 NumNni: int(options.Olt.NniPorts),
Elia Battiston420c9092022-02-02 12:17:54 +0100136 NniSpeed: options.Olt.NniSpeed,
Matteo Scandolo96f89192021-03-12 13:17:26 -0800137 NumPon: int(options.Olt.PonPorts),
138 NumOnuPerPon: int(options.Olt.OnusPonPort),
Mahir Gunyela1753ae2021-06-23 00:24:56 -0700139 NumUni: int(options.Olt.UniPorts),
Elia Battistonac63b112022-01-12 18:40:49 +0100140 NumPots: int(options.Olt.PotsPorts),
Matteo Scandolo96f89192021-03-12 13:17:26 -0800141 Pons: []*PonPort{},
142 Nnis: []*NniPort{},
143 Delay: options.BBSim.Delay,
144 enablePerf: options.BBSim.EnablePerf,
145 PublishEvents: options.BBSim.Events,
146 PortStatsInterval: options.Olt.PortStatsInterval,
147 dhcpServer: dhcp.NewDHCPServer(),
148 PreviouslyConnected: false,
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800149 AllocIDs: make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
150 GemPortIDs: make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool),
Holger Hildebrandtc10bab12021-04-27 09:23:48 +0000151 OmciResponseRate: options.Olt.OmciResponseRate,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700152 }
153
Pragya Arya996a0892020-03-09 21:47:52 +0530154 if val, ok := ControlledActivationModes[options.BBSim.ControlledActivation]; ok {
Pragya Arya2225f202020-01-29 18:05:01 +0530155 olt.ControlledActivation = val
156 } else {
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700157 // FIXME throw an error if the ControlledActivation is not valid
Pragya Arya2225f202020-01-29 18:05:01 +0530158 oltLogger.Warn("Unknown ControlledActivation Mode given, running in Default mode")
159 olt.ControlledActivation = Default
160 }
161
Matteo Scandolo4747d292019-08-05 11:50:18 -0700162 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700163 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700164 olt.InternalState = fsm.NewFSM(
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100165 OltInternalStateCreated,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700166 fsm.Events{
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100167 {Name: OltInternalTxInitialize, Src: []string{OltInternalStateCreated, OltInternalStateDeleted}, Dst: OltInternalStateInitialized},
168 {Name: OltInternalTxEnable, Src: []string{OltInternalStateInitialized, OltInternalStateDisabled}, Dst: OltInternalStateEnabled},
169 {Name: OltInternalTxDisable, Src: []string{OltInternalStateEnabled}, Dst: OltInternalStateDisabled},
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700170 // delete event in enabled state below is for reboot OLT case.
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100171 {Name: OltInternalTxDelete, Src: []string{OltInternalStateDisabled, OltInternalStateEnabled}, Dst: OltInternalStateDeleted},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700172 },
173 fsm.Callbacks{
174 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700175 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700176 },
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100177 fmt.Sprintf("enter_%s", OltInternalStateInitialized): func(e *fsm.Event) { olt.InitOlt() },
178 fmt.Sprintf("enter_%s", OltInternalStateDeleted): func(e *fsm.Event) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800179 // remove all the resource allocations
180 olt.clearAllResources()
181 },
Matteo Scandolo4747d292019-08-05 11:50:18 -0700182 },
183 )
184
Shrey Baid688b4242020-07-10 20:40:10 +0530185 if !isMock {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700186 // create NNI Port
187 nniPort, err := CreateNNI(&olt)
188 if err != nil {
189 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
190 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700191
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700192 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700193 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700194
Matteo Scandolo4a036262020-08-17 15:56:13 -0700195 // Create device and Services
Matteo Scandolo4a036262020-08-17 15:56:13 -0700196 nextCtag := map[string]int{}
197 nextStag := map[string]int{}
198
Matteo Scandolo4747d292019-08-05 11:50:18 -0700199 // create PON ports
Matteo Scandolo4a036262020-08-17 15:56:13 -0700200 for i := 0; i < olt.NumPon; i++ {
Elia Battistonb7bea222022-02-18 16:25:00 +0100201 ponConf, err := common.GetPonConfigById(uint32(i))
202 if err != nil {
203 oltLogger.WithFields(log.Fields{
204 "Err": err,
205 "IntfId": i,
206 }).Fatal("cannot-get-pon-configuration")
207 }
208
209 tech, err := common.PonTechnologyFromString(ponConf.Technology)
210 if err != nil {
211 oltLogger.WithFields(log.Fields{
212 "Err": err,
213 "IntfId": i,
214 }).Fatal("unkown-pon-port-technology")
215 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800216
217 // initialize the resource maps for every PON Ports
218 olt.AllocIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
219 olt.GemPortIDs[uint32(i)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
220
Elia Battistonb7bea222022-02-18 16:25:00 +0100221 p := CreatePonPort(&olt, uint32(i), tech)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700222
Matteo Scandolo4a036262020-08-17 15:56:13 -0700223 // create ONU devices
Elia Battistonb7bea222022-02-18 16:25:00 +0100224 if (ponConf.OnuRange.EndId - ponConf.OnuRange.StartId + 1) < uint32(olt.NumOnuPerPon) {
225 oltLogger.WithFields(log.Fields{
226 "OnuRange": ponConf.OnuRange,
227 "RangeSize": ponConf.OnuRange.EndId - ponConf.OnuRange.StartId + 1,
228 "NumOnuPerPon": olt.NumOnuPerPon,
229 "IntfId": i,
230 }).Fatal("onus-per-pon-bigger-than-resource-range-size")
231 }
232
Matteo Scandolo4a036262020-08-17 15:56:13 -0700233 for j := 0; j < olt.NumOnuPerPon; j++ {
234 delay := time.Duration(olt.Delay*j) * time.Millisecond
Matteo Scandolo8a574812021-05-20 15:18:53 -0700235 o := CreateONU(&olt, p, uint32(j+1), delay, nextCtag, nextStag, isMock)
Matteo Scandolof65e6872020-04-15 15:18:43 -0700236
Matteo Scandolo4a036262020-08-17 15:56:13 -0700237 p.Onus = append(p.Onus, o)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700238 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700239 olt.Pons = append(olt.Pons, p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700240 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100241
Shrey Baid688b4242020-07-10 20:40:10 +0530242 if !isMock {
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100243 if err := olt.InternalState.Event(OltInternalTxInitialize); err != nil {
Matteo Scandolod32c3822019-11-26 15:57:46 -0700244 log.Errorf("Error initializing OLT: %v", err)
245 return nil
246 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100247 }
248
Pragya Arya324337e2020-02-20 14:35:08 +0530249 if olt.PublishEvents {
250 log.Debugf("BBSim event publishing is enabled")
251 // Create a channel to write event messages
252 olt.EventChannel = make(chan common.Event, 100)
253 }
254
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700255 return &olt
256}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700257
Shrey Baid688b4242020-07-10 20:40:10 +0530258func (o *OltDevice) InitOlt() {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100259
Hardik Windlassefdb4b62021-03-18 10:33:24 +0000260 if o.OltServer == nil {
261 o.OltServer, _ = o.StartOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100262 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800263 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100264 }
265
266 // create new channel for processOltMessages Go routine
Matteo Scandolof9d43412021-01-12 11:11:34 -0800267 o.channel = make(chan types.Message)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100268
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100269 // FIXME we are assuming we have only one NNI
270 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800271 // NOTE we want to make sure the state is down when we initialize the OLT,
272 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
273 // in-band management
274 o.Nnis[0].OperState.SetState("down")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100275 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800276
277 for ponId := range o.Pons {
278 // initialize the resource maps for every PON Ports
279 olt.AllocIDs[uint32(ponId)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
280 olt.GemPortIDs[uint32(ponId)] = make(map[uint32]map[uint32]map[int32]map[uint64]bool)
281 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700282}
283
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800284func (o *OltDevice) RestartOLT() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100285
Matteo Scandolo96f89192021-03-12 13:17:26 -0800286 o.PreviouslyConnected = false
287
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700288 softReboot := false
Matteo Scandolo4a036262020-08-17 15:56:13 -0700289 rebootDelay := common.Config.Olt.OltRebootDelay
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800290
291 oltLogger.WithFields(log.Fields{
292 "oltId": o.ID,
293 }).Infof("Simulating OLT restart... (%ds)", rebootDelay)
294
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100295 if o.InternalState.Is(OltInternalStateEnabled) {
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700296 oltLogger.WithFields(log.Fields{
297 "oltId": o.ID,
298 }).Info("This is an OLT soft reboot")
299 softReboot = true
300 }
301
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800302 // transition internal state to deleted
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100303 if err := o.InternalState.Event(OltInternalTxDelete); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800304 oltLogger.WithFields(log.Fields{
305 "oltId": o.ID,
306 }).Errorf("Error deleting OLT: %v", err)
307 return err
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100308 }
309
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700310 if softReboot {
311 for _, pon := range o.Pons {
312 if pon.InternalState.Current() == "enabled" {
313 // disable PONs
Matteo Scandolof9d43412021-01-12 11:11:34 -0800314 msg := types.Message{
315 Type: types.PonIndication,
316 Data: types.PonIndicationMessage{
317 OperState: types.DOWN,
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700318 PonPortID: pon.ID,
319 },
320 }
321 o.channel <- msg
322 }
323
324 for _, onu := range pon.Onus {
Andrea Campanella8ad54a42022-03-09 14:36:55 +0100325 err := onu.InternalState.Event(OnuTxDisable)
326 oltLogger.WithFields(log.Fields{
327 "oltId": o.ID,
328 "onuId": onu.ID,
329 }).Errorf("Error disabling ONUs on OLT soft reboot: %v", err)
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700330 }
331 }
332 } else {
333 // PONs are already handled in the Disable call
334 for _, pon := range olt.Pons {
335 // ONUs are not automatically disabled when a PON goes down
336 // as it's possible that it's an admin down and in that case the ONUs need to keep their state
337 for _, onu := range pon.Onus {
Andrea Campanella8ad54a42022-03-09 14:36:55 +0100338 err := onu.InternalState.Event(OnuTxDisable)
339 oltLogger.WithFields(log.Fields{
340 "oltId": o.ID,
341 "onuId": onu.ID,
342 }).Errorf("Error disabling ONUs on OLT reboot: %v", err)
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700343 }
Pragya Arya2225f202020-01-29 18:05:01 +0530344 }
345 }
346
Matteo Scandolob307d8a2021-05-10 15:19:27 -0700347 time.Sleep(1 * time.Second) // we need to give the OLT the time to respond to all the pending gRPC request before stopping the server
348 o.StopOltServer()
349
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100350 // terminate the OLT's processOltMessages go routine
351 close(o.channel)
Matteo Scandolo90d08f62020-10-29 12:06:55 -0700352
Andrea Campanella8ad54a42022-03-09 14:36:55 +0100353 oltLogger.WithFields(log.Fields{
354 "oltId": o.ID,
355 }).Infof("Waiting OLT restart for... (%ds)", rebootDelay)
356
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100357 //Prevents Enable to progress before the reboot is completed (VOL-4616)
358 o.Lock()
Matteo Scandoloe9f5a6b2020-09-16 15:54:38 -0700359 o.enableContextCancel()
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100360 time.Sleep(time.Duration(rebootDelay) * time.Second)
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100361 o.Unlock()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100362
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100363 if err := o.InternalState.Event(OltInternalTxInitialize); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800364 oltLogger.WithFields(log.Fields{
365 "oltId": o.ID,
366 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100367 return err
368 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800369 oltLogger.WithFields(log.Fields{
370 "oltId": o.ID,
371 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100372 return nil
373}
374
375// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800376func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700377 address := common.Config.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700378 lis, err := net.Listen("tcp", address)
379 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700380 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700381 }
382 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100383
Matteo Scandolo4747d292019-08-05 11:50:18 -0700384 openolt.RegisterOpenoltServer(grpcServer, o)
385
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100386 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700387
Shrey Baid688b4242020-07-10 20:40:10 +0530388 go func() { _ = grpcServer.Serve(lis) }()
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100389 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700390
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100391 return grpcServer, nil
392}
393
Matteo Scandolo88c204a2020-11-03 10:34:24 -0800394// StartOltServer will create the grpc server that VOLTHA uses
395// to communicate with the device
396func (o *OltDevice) StartOltServer() (*grpc.Server, error) {
397 oltServer, err := o.newOltServer()
398 if err != nil {
399 oltLogger.WithFields(log.Fields{
400 "err": err,
401 }).Error("Cannot OLT gRPC server")
402 return nil, err
403 }
404 return oltServer, nil
405}
406
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100407// StopOltServer stops the OpenOLT grpc server
Matteo Scandolo88c204a2020-11-03 10:34:24 -0800408func (o *OltDevice) StopOltServer() {
Hardik Windlassefdb4b62021-03-18 10:33:24 +0000409 if o.OltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800410 oltLogger.WithFields(log.Fields{
411 "oltId": o.SerialNumber,
412 }).Warnf("Stopping OLT gRPC server")
Hardik Windlassefdb4b62021-03-18 10:33:24 +0000413 o.OltServer.Stop()
414 o.OltServer = nil
Andrea Campanella8ad54a42022-03-09 14:36:55 +0100415 } else {
416 oltLogger.WithFields(log.Fields{
417 "oltId": o.SerialNumber,
418 }).Warnf("OLT gRPC server is already stopped")
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700419 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700420}
421
422// Device Methods
423
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100424// Enable implements the OpenOLT EnableIndicationServer functionality
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100425func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700426 oltLogger.Debug("Enable OLT called")
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100427
428 if o.InternalState.Is(OltInternalStateDeleted) {
429 err := fmt.Errorf("Cannot enable OLT while it is rebooting")
430 oltLogger.WithFields(log.Fields{
431 "oltId": o.SerialNumber,
432 "internalState": o.InternalState.Current(),
433 }).Error(err)
434 return err
435 }
436
Pragya Arya2225f202020-01-29 18:05:01 +0530437 rebootFlag := false
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700438
David Bainbridge103cf022019-12-16 20:11:35 +0000439 // If enabled has already been called then an enabled context has
440 // been created. If this is the case then we want to cancel all the
441 // proessing loops associated with that enable before we recreate
442 // new ones
443 o.Lock()
444 if o.enableContext != nil && o.enableContextCancel != nil {
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700445 oltLogger.Info("This is an OLT reboot or a reconcile")
David Bainbridge103cf022019-12-16 20:11:35 +0000446 o.enableContextCancel()
Pragya Arya2225f202020-01-29 18:05:01 +0530447 rebootFlag = true
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700448 time.Sleep(1 * time.Second)
David Bainbridge103cf022019-12-16 20:11:35 +0000449 }
450 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
451 o.Unlock()
452
Matteo Scandolo4747d292019-08-05 11:50:18 -0700453 wg := sync.WaitGroup{}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700454
Matteo Scandolo4a036262020-08-17 15:56:13 -0700455 o.OpenoltStream = stream
Pragya Arya1cbefa42020-01-13 12:15:29 +0530456
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100457 // create Go routine to process all OLT events
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700458 wg.Add(1)
David Bainbridge103cf022019-12-16 20:11:35 +0000459 go o.processOltMessages(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700460
461 // enable the OLT
Matteo Scandolof9d43412021-01-12 11:11:34 -0800462 oltMsg := types.Message{
463 Type: types.OltIndication,
464 Data: types.OltIndicationMessage{
465 OperState: types.UP,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700466 },
467 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100468 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700469
470 // send NNI Port Indications
471 for _, nni := range o.Nnis {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800472 msg := types.Message{
473 Type: types.NniIndication,
474 Data: types.NniIndicationMessage{
475 OperState: types.UP,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700476 NniPortID: nni.ID,
477 },
478 }
479 o.channel <- msg
480 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100481
Shrey Baid688b4242020-07-10 20:40:10 +0530482 if rebootFlag {
Pragya Arya2225f202020-01-29 18:05:01 +0530483 for _, pon := range o.Pons {
484 if pon.InternalState.Current() == "disabled" {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800485 msg := types.Message{
486 Type: types.PonIndication,
487 Data: types.PonIndicationMessage{
488 OperState: types.UP,
Pragya Arya2225f202020-01-29 18:05:01 +0530489 PonPortID: pon.ID,
490 },
491 }
492 o.channel <- msg
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000493 }
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700494 // when the enableContext was canceled the ONUs stopped listening on the channel
495 for _, onu := range pon.Onus {
496 go onu.ProcessOnuMessages(o.enableContext, stream, nil)
497
498 // update the stream on all the services
Matteo Scandolo8a574812021-05-20 15:18:53 -0700499 for _, uni := range onu.UniPorts {
500 uni.UpdateStream(stream)
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700501 }
502 }
Pragya Arya2225f202020-01-29 18:05:01 +0530503 }
504 } else {
505
506 // 1. controlledActivation == Default: Send both PON and ONUs indications
507 // 2. controlledActivation == only-onu: that means only ONUs will be controlled activated, so auto send PON indications
508
509 if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
510 // send PON Port indications
511 for _, pon := range o.Pons {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800512 msg := types.Message{
513 Type: types.PonIndication,
514 Data: types.PonIndicationMessage{
515 OperState: types.UP,
Pragya Arya2225f202020-01-29 18:05:01 +0530516 PonPortID: pon.ID,
517 },
518 }
519 o.channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700520 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700521 }
522 }
523
Pragya Arya996a0892020-03-09 21:47:52 +0530524 if !o.enablePerf {
525 // Start a go routine to send periodic port stats to openolt adapter
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700526 wg.Add(1)
527 go o.periodicPortStats(o.enableContext, &wg, stream)
Pragya Arya996a0892020-03-09 21:47:52 +0530528 }
529
Matteo Scandolo4747d292019-08-05 11:50:18 -0700530 wg.Wait()
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700531 oltLogger.WithFields(log.Fields{
532 "stream": stream,
533 }).Debug("OpenOLT Stream closed")
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100534
535 return nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700536}
537
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700538func (o *OltDevice) periodicPortStats(ctx context.Context, wg *sync.WaitGroup, stream openolt.Openolt_EnableIndicationServer) {
Pragya Arya996a0892020-03-09 21:47:52 +0530539 var portStats *openolt.PortStatistics
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700540
541loop:
Pragya Arya996a0892020-03-09 21:47:52 +0530542 for {
543 select {
544 case <-time.After(time.Duration(o.PortStatsInterval) * time.Second):
545 // send NNI port stats
546 for _, port := range o.Nnis {
547 incrementStat := true
548 if port.OperState.Current() == "down" {
549 incrementStat = false
550 }
551 portStats, port.PacketCount = getPortStats(port.PacketCount, incrementStat)
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700552 o.sendPortStatsIndication(portStats, port.ID, port.Type, stream)
Pragya Arya996a0892020-03-09 21:47:52 +0530553 }
554
555 // send PON port stats
556 for _, port := range o.Pons {
557 incrementStat := true
558 // do not increment port stats if PON port is down or no ONU is activated on PON port
559 if port.OperState.Current() == "down" || port.GetNumOfActiveOnus() < 1 {
560 incrementStat = false
561 }
562 portStats, port.PacketCount = getPortStats(port.PacketCount, incrementStat)
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700563 o.sendPortStatsIndication(portStats, port.ID, port.Type, stream)
Pragya Arya996a0892020-03-09 21:47:52 +0530564 }
565 case <-ctx.Done():
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700566 oltLogger.Debug("Stop sending port stats")
567 break loop
Pragya Arya996a0892020-03-09 21:47:52 +0530568 }
Pragya Arya996a0892020-03-09 21:47:52 +0530569 }
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700570 wg.Done()
Pragya Arya996a0892020-03-09 21:47:52 +0530571}
572
Matteo Scandolo4747d292019-08-05 11:50:18 -0700573// Helpers method
574
Matteo Scandolof9d43412021-01-12 11:11:34 -0800575func (o *OltDevice) SetAlarm(interfaceId uint32, interfaceType string, alarmStatus string) error {
576
577 switch interfaceType {
578 case "nni":
579 if !o.HasNni(interfaceId) {
580 return status.Errorf(codes.NotFound, strconv.Itoa(int(interfaceId))+" NNI not present in olt")
581 }
582
583 case "pon":
584 if !o.HasPon(interfaceId) {
585 return status.Errorf(codes.NotFound, strconv.Itoa(int(interfaceId))+" PON not present in olt")
586 }
587 }
588
589 alarmIndication := &openolt.AlarmIndication{
590 Data: &openolt.AlarmIndication_LosInd{LosInd: &openolt.LosIndication{
591 Status: alarmStatus,
592 IntfId: InterfaceIDToPortNo(interfaceId, interfaceType),
593 }},
594 }
595
596 msg := types.Message{
597 Type: types.AlarmIndication,
598 Data: alarmIndication,
599 }
600
601 o.channel <- msg
602
603 return nil
604}
605
606func (o *OltDevice) HasNni(id uint32) bool {
607 for _, intf := range o.Nnis {
608 if intf.ID == id {
609 return true
610 }
611 }
612 return false
613}
614
615func (o *OltDevice) HasPon(id uint32) bool {
616 for _, intf := range o.Pons {
617 if intf.ID == id {
618 return true
619 }
620 }
621 return false
622}
623
Shrey Baid688b4242020-07-10 20:40:10 +0530624func (o *OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700625 for _, pon := range o.Pons {
626 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700627 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700628 }
629 }
Shrey Baid688b4242020-07-10 20:40:10 +0530630 return nil, fmt.Errorf("Cannot find PonPort with id %d in OLT %d", id, o.ID)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700631}
632
Shrey Baid688b4242020-07-10 20:40:10 +0530633func (o *OltDevice) getNniById(id uint32) (*NniPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700634 for _, nni := range o.Nnis {
635 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700636 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700637 }
638 }
Shrey Baid688b4242020-07-10 20:40:10 +0530639 return nil, fmt.Errorf("Cannot find NniPort with id %d in OLT %d", id, o.ID)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700640}
641
Scott Baker41724b82020-01-21 19:54:53 -0800642func (o *OltDevice) sendAlarmIndication(alarmInd *openolt.AlarmIndication, stream openolt.Openolt_EnableIndicationServer) {
643 data := &openolt.Indication_AlarmInd{AlarmInd: alarmInd}
644 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
645 oltLogger.Errorf("Failed to send Alarm Indication: %v", err)
646 return
647 }
648
649 oltLogger.WithFields(log.Fields{
650 "AlarmIndication": alarmInd,
651 }).Debug("Sent Indication_AlarmInd")
652}
653
Matteo Scandolof9d43412021-01-12 11:11:34 -0800654func (o *OltDevice) sendOltIndication(msg types.OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700655 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
656 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700657 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800658 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700659 }
660
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700661 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700662 "OperState": msg.OperState,
663 }).Debug("Sent Indication_OltInd")
664}
665
Matteo Scandolof9d43412021-01-12 11:11:34 -0800666func (o *OltDevice) sendNniIndication(msg types.NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700667 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800668 if msg.OperState == types.UP {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800669 if err := nni.OperState.Event("enable"); err != nil {
670 log.WithFields(log.Fields{
671 "Type": nni.Type,
672 "IntfId": nni.ID,
673 "OperState": nni.OperState.Current(),
674 }).Errorf("Can't move NNI Port to enabled state: %v", err)
675 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800676 } else if msg.OperState == types.DOWN {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800677 if err := nni.OperState.Event("disable"); err != nil {
678 log.WithFields(log.Fields{
679 "Type": nni.Type,
680 "IntfId": nni.ID,
681 "OperState": nni.OperState.Current(),
682 }).Errorf("Can't move NNI Port to disable state: %v", err)
683 }
684 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700685 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700686 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700687 Type: nni.Type,
688 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700689 OperState: nni.OperState.Current(),
Elia Battiston420c9092022-02-02 12:17:54 +0100690 Speed: o.NniSpeed,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700691 }}
692
693 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700694 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800695 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700696 }
697
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700698 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700699 "Type": nni.Type,
700 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700701 "OperState": nni.OperState.Current(),
Elia Battiston420c9092022-02-02 12:17:54 +0100702 "Speed": o.NniSpeed,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700703 }).Debug("Sent Indication_IntfOperInd for NNI")
704}
705
Pragya Arya2225f202020-01-29 18:05:01 +0530706func (o *OltDevice) sendPonIndication(ponPortID uint32) {
707
Matteo Scandolo4a036262020-08-17 15:56:13 -0700708 stream := o.OpenoltStream
Pragya Arya2225f202020-01-29 18:05:01 +0530709 pon, _ := o.GetPonById(ponPortID)
710 // Send IntfIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700711 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700712 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700713 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700714 }}
715
716 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700717 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800718 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700719 }
720
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700721 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700722 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700723 "OperState": pon.OperState.Current(),
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700724 }).Debug("Sent Indication_IntfInd for PON")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700725
Pragya Arya2225f202020-01-29 18:05:01 +0530726 // Send IntfOperIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700727 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700728 Type: pon.Type,
729 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700730 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700731 }}
732
733 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700734 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800735 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700736 }
737
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700738 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700739 "Type": pon.Type,
740 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700741 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700742 }).Debug("Sent Indication_IntfOperInd for PON")
743}
744
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700745func (o *OltDevice) sendPortStatsIndication(stats *openolt.PortStatistics, portID uint32, portType string, stream openolt.Openolt_EnableIndicationServer) {
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100746 if o.InternalState.Current() == OltInternalStateEnabled {
Shrey Baid55f328c2020-07-07 19:20:42 +0530747 oltLogger.WithFields(log.Fields{
748 "Type": portType,
749 "IntfId": portID,
750 }).Trace("Sending port stats")
751 stats.IntfId = InterfaceIDToPortNo(portID, portType)
752 data := &openolt.Indication_PortStats{
753 PortStats: stats,
754 }
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700755
Shrey Baid55f328c2020-07-07 19:20:42 +0530756 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
757 oltLogger.Errorf("Failed to send PortStats: %v", err)
758 return
759 }
Pragya Arya996a0892020-03-09 21:47:52 +0530760 }
761}
762
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100763// processOltMessages handles messages received over the OpenOLT interface
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700764func (o *OltDevice) processOltMessages(ctx context.Context, stream types.Stream, wg *sync.WaitGroup) {
765 oltLogger.WithFields(log.Fields{
766 "stream": stream,
767 }).Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000768 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700769
David Bainbridge103cf022019-12-16 20:11:35 +0000770loop:
771 for {
772 select {
773 case <-ctx.Done():
774 oltLogger.Debug("OLT Indication processing canceled via context")
775 break loop
Matteo Scandoloba3e9cd2021-05-14 16:19:54 -0700776 // do not terminate this loop if the stream is closed,
777 // when we restart the gRPC server it will automatically reconnect and we need this loop to send indications
778 //case <-stream.Context().Done():
779 // oltLogger.Debug("OLT Indication processing canceled via stream context")
780 // break loop
David Bainbridge103cf022019-12-16 20:11:35 +0000781 case message, ok := <-ch:
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700782 if !ok {
783 if ctx.Err() != nil {
784 oltLogger.WithField("err", ctx.Err()).Error("OLT EnableContext error")
785 }
786 oltLogger.Warn("OLT Indication processing canceled via closed channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000787 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700788 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700789
David Bainbridge103cf022019-12-16 20:11:35 +0000790 oltLogger.WithFields(log.Fields{
791 "oltId": o.ID,
792 "messageType": message.Type,
793 }).Trace("Received message")
794
795 switch message.Type {
Matteo Scandolof9d43412021-01-12 11:11:34 -0800796 case types.OltIndication:
797 msg, _ := message.Data.(types.OltIndicationMessage)
798 if msg.OperState == types.UP {
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100799 _ = o.InternalState.Event(OltInternalTxEnable)
Shrey Baid688b4242020-07-10 20:40:10 +0530800 _ = o.OperState.Event("enable")
Matteo Scandolof9d43412021-01-12 11:11:34 -0800801 } else if msg.OperState == types.DOWN {
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100802 _ = o.InternalState.Event(OltInternalTxDisable)
Shrey Baid688b4242020-07-10 20:40:10 +0530803 _ = o.OperState.Event("disable")
David Bainbridge103cf022019-12-16 20:11:35 +0000804 }
805 o.sendOltIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800806 case types.AlarmIndication:
Scott Baker41724b82020-01-21 19:54:53 -0800807 alarmInd, _ := message.Data.(*openolt.AlarmIndication)
808 o.sendAlarmIndication(alarmInd, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800809 case types.NniIndication:
810 msg, _ := message.Data.(types.NniIndicationMessage)
David Bainbridge103cf022019-12-16 20:11:35 +0000811 o.sendNniIndication(msg, stream)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800812 case types.PonIndication:
813 msg, _ := message.Data.(types.PonIndicationMessage)
Pragya Arya2225f202020-01-29 18:05:01 +0530814 pon, _ := o.GetPonById(msg.PonPortID)
Matteo Scandolof9d43412021-01-12 11:11:34 -0800815 if msg.OperState == types.UP {
Hardik Windlassad790cb2020-06-17 21:26:22 +0530816 if err := pon.OperState.Event("enable"); err != nil {
817 oltLogger.WithFields(log.Fields{
818 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800819 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530820 }).Error("Can't Enable Oper state for PON Port")
821 }
822 if err := pon.InternalState.Event("enable"); err != nil {
823 oltLogger.WithFields(log.Fields{
824 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800825 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530826 }).Error("Can't Enable Internal state for PON Port")
827 }
Matteo Scandolof9d43412021-01-12 11:11:34 -0800828 } else if msg.OperState == types.DOWN {
Hardik Windlassad790cb2020-06-17 21:26:22 +0530829 if err := pon.OperState.Event("disable"); err != nil {
830 oltLogger.WithFields(log.Fields{
831 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800832 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530833 }).Error("Can't Disable Oper state for PON Port")
834 }
835 if err := pon.InternalState.Event("disable"); err != nil {
836 oltLogger.WithFields(log.Fields{
837 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800838 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530839 }).Error("Can't Disable Internal state for PON Port")
840 }
Pragya Arya2225f202020-01-29 18:05:01 +0530841 }
David Bainbridge103cf022019-12-16 20:11:35 +0000842 default:
843 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
844 }
845 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700846 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100847 wg.Done()
Matteo Scandolo9ddb3a92021-04-14 16:16:20 -0700848 oltLogger.WithFields(log.Fields{
849 "stream": stream,
850 }).Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700851}
852
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700853// returns an ONU with a given Serial Number
Shrey Baid688b4242020-07-10 20:40:10 +0530854func (o *OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700855 // NOTE this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700856 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700857 for _, pon := range o.Pons {
858 for _, onu := range pon.Onus {
859 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700860 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700861 }
862 }
863 }
864
Shrey Baid688b4242020-07-10 20:40:10 +0530865 return &Onu{}, fmt.Errorf("cannot-find-onu-by-serial-number-%s", serialNumber)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700866}
867
William Kurkian9dadc5b2019-10-22 13:51:57 -0400868// returns an ONU with a given interface/Onu Id
Shrey Baid688b4242020-07-10 20:40:10 +0530869func (o *OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700870 // NOTE this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400871 // memoizing it will remove the bottleneck
872 for _, pon := range o.Pons {
873 if pon.ID == intfId {
874 for _, onu := range pon.Onus {
875 if onu.ID == onuId {
876 return onu, nil
877 }
878 }
879 }
880 }
Shrey Baid688b4242020-07-10 20:40:10 +0530881 return &Onu{}, fmt.Errorf("cannot-find-onu-by-id-%v-%v", intfId, onuId)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400882}
883
Matteo Scandolo4a036262020-08-17 15:56:13 -0700884// returns a Service with a given Mac Address
885func (o *OltDevice) FindServiceByMacAddress(mac net.HardwareAddr) (ServiceIf, error) {
Matteo Scandolo8a574812021-05-20 15:18:53 -0700886 // NOTE this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700887 // memoizing it will remove the bottleneck
888 for _, pon := range o.Pons {
889 for _, onu := range pon.Onus {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700890 s, err := onu.findServiceByMacAddress(mac)
891 if err == nil {
892 return s, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700893 }
894 }
895 }
896
Matteo Scandolo4a036262020-08-17 15:56:13 -0700897 return nil, fmt.Errorf("cannot-find-service-by-mac-address-%s", mac)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700898}
899
Matteo Scandolo4747d292019-08-05 11:50:18 -0700900// GRPC Endpoints
901
Shrey Baid688b4242020-07-10 20:40:10 +0530902func (o *OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700903
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700904 pon, _ := o.GetPonById(onu.IntfId)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800905
Matteo Scandolo8a574812021-05-20 15:18:53 -0700906 // Enable the resource maps for this ONU
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800907 olt.AllocIDs[onu.IntfId][onu.OnuId] = make(map[uint32]map[int32]map[uint64]bool)
908 olt.GemPortIDs[onu.IntfId][onu.OnuId] = make(map[uint32]map[int32]map[uint64]bool)
909
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700910 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
Matteo Scandoloba3e9cd2021-05-14 16:19:54 -0700911
912 publishEvent("ONU-activate-indication-received", int32(onu.IntfId), int32(onu.OnuId), _onu.Sn())
913 oltLogger.WithFields(log.Fields{
914 "OnuSn": _onu.Sn(),
915 }).Info("Received ActivateOnu call from VOLTHA")
916
William Kurkian0418bc82019-11-06 12:16:24 -0500917 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700918
Matteo Scandolocedde462021-03-09 17:37:16 -0800919 if err := _onu.InternalState.Event(OnuTxEnable); err != nil {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700920 oltLogger.WithFields(log.Fields{
921 "IntfId": _onu.PonPortID,
922 "OnuSn": _onu.Sn(),
923 "OnuId": _onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -0800924 }).Infof("Failed to transition ONU to %s state: %s", OnuStateEnabled, err.Error())
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700925 }
926
927 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
928
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700929 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700930}
931
Matteo Scandolo4b077aa2021-02-16 17:33:37 -0800932func (o *OltDevice) DeactivateOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700933 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700934 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700935}
936
Shrey Baid688b4242020-07-10 20:40:10 +0530937func (o *OltDevice) DeleteOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Pragya Arya1cbefa42020-01-13 12:15:29 +0530938 oltLogger.WithFields(log.Fields{
939 "IntfId": onu.IntfId,
940 "OnuId": onu.OnuId,
941 }).Info("Received DeleteOnu call from VOLTHA")
942
943 pon, err := o.GetPonById(onu.IntfId)
944 if err != nil {
945 oltLogger.WithFields(log.Fields{
946 "OnuId": onu.OnuId,
947 "IntfId": onu.IntfId,
948 "err": err,
949 }).Error("Can't find PonPort")
950 }
951 _onu, err := pon.GetOnuById(onu.OnuId)
952 if err != nil {
953 oltLogger.WithFields(log.Fields{
954 "OnuId": onu.OnuId,
955 "IntfId": onu.IntfId,
956 "err": err,
957 }).Error("Can't find Onu")
958 }
959
Matteo Scandolocedde462021-03-09 17:37:16 -0800960 if err := _onu.InternalState.Event(OnuTxDisable); err != nil {
Pragya Arya1cbefa42020-01-13 12:15:29 +0530961 oltLogger.WithFields(log.Fields{
962 "IntfId": _onu.PonPortID,
963 "OnuSn": _onu.Sn(),
964 "OnuId": _onu.ID,
Matteo Scandolocedde462021-03-09 17:37:16 -0800965 }).Infof("Failed to transition ONU to %s state: %s", OnuStateDisabled, err.Error())
Hardik Windlassad790cb2020-06-17 21:26:22 +0530966 }
967
Hardik Windlassad790cb2020-06-17 21:26:22 +0530968 // ONU Re-Discovery
Elia Battiston67e9e4c2022-02-15 16:38:40 +0100969 if o.InternalState.Current() == OltInternalStateEnabled && pon.InternalState.Current() == "enabled" {
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530970 go _onu.ReDiscoverOnu()
Pragya Arya1cbefa42020-01-13 12:15:29 +0530971 }
972
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700973 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700974}
975
Shrey Baid688b4242020-07-10 20:40:10 +0530976func (o *OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700977 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800978 oltLogger.WithFields(log.Fields{
979 "oltId": o.ID,
980 }).Info("Disabling OLT")
Pragya Arya324337e2020-02-20 14:35:08 +0530981 publishEvent("OLT-disable-received", -1, -1, "")
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800982
Matteo Scandolo401503a2019-12-11 14:48:14 -0800983 for _, pon := range o.Pons {
Pragya Arya2225f202020-01-29 18:05:01 +0530984 if pon.InternalState.Current() == "enabled" {
985 // disable PONs
Matteo Scandolof9d43412021-01-12 11:11:34 -0800986 msg := types.Message{
987 Type: types.PonIndication,
988 Data: types.PonIndicationMessage{
989 OperState: types.DOWN,
Pragya Arya2225f202020-01-29 18:05:01 +0530990 PonPortID: pon.ID,
991 },
992 }
993 o.channel <- msg
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800994 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800995 }
996
Matteo Scandolo401503a2019-12-11 14:48:14 -0800997 // Note that we are not disabling the NNI as the real OLT does not.
998 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800999
1000 // disable OLT
Matteo Scandolof9d43412021-01-12 11:11:34 -08001001 oltMsg := types.Message{
1002 Type: types.OltIndication,
1003 Data: types.OltIndicationMessage{
1004 OperState: types.DOWN,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001005 },
1006 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +01001007 o.channel <- oltMsg
Matteo Scandoloba3e9cd2021-05-14 16:19:54 -07001008
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001009 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001010}
1011
Shrey Baid688b4242020-07-10 20:40:10 +05301012func (o *OltDevice) DisablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
Hardik Windlassad790cb2020-06-17 21:26:22 +05301013 oltLogger.Infof("DisablePonIf request received for PON %d", intf.IntfId)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001014 ponID := intf.GetIntfId()
1015 pon, _ := o.GetPonById(intf.IntfId)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001016
Matteo Scandolof9d43412021-01-12 11:11:34 -08001017 msg := types.Message{
1018 Type: types.PonIndication,
1019 Data: types.PonIndicationMessage{
1020 OperState: types.DOWN,
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001021 PonPortID: ponID,
1022 },
1023 }
1024 o.channel <- msg
1025
1026 for _, onu := range pon.Onus {
1027
Matteo Scandolof9d43412021-01-12 11:11:34 -08001028 onuIndication := types.OnuIndicationMessage{
1029 OperState: types.DOWN,
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001030 PonPortID: ponID,
1031 OnuID: onu.ID,
1032 OnuSN: onu.SerialNumber,
1033 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001034 onu.sendOnuIndication(onuIndication, o.OpenoltStream)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001035
1036 }
1037
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001038 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001039}
1040
Zdravko Bozakov681364d2019-11-10 14:28:46 +01001041func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001042 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Pragya Arya324337e2020-02-20 14:35:08 +05301043 publishEvent("OLT-enable-received", -1, -1, "")
Elia Battiston67e9e4c2022-02-15 16:38:40 +01001044 return o.Enable(stream)
Matteo Scandolo4747d292019-08-05 11:50:18 -07001045}
1046
Shrey Baid688b4242020-07-10 20:40:10 +05301047func (o *OltDevice) EnablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
Hardik Windlassad790cb2020-06-17 21:26:22 +05301048 oltLogger.Infof("EnablePonIf request received for PON %d", intf.IntfId)
Pragya Arya2225f202020-01-29 18:05:01 +05301049 ponID := intf.GetIntfId()
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001050 pon, _ := o.GetPonById(intf.IntfId)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001051
Matteo Scandolof9d43412021-01-12 11:11:34 -08001052 msg := types.Message{
1053 Type: types.PonIndication,
1054 Data: types.PonIndicationMessage{
1055 OperState: types.UP,
Pragya Arya2225f202020-01-29 18:05:01 +05301056 PonPortID: ponID,
1057 },
1058 }
1059 o.channel <- msg
1060
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001061 for _, onu := range pon.Onus {
1062
Matteo Scandolof9d43412021-01-12 11:11:34 -08001063 onuIndication := types.OnuIndicationMessage{
1064 OperState: types.UP,
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001065 PonPortID: ponID,
1066 OnuID: onu.ID,
1067 OnuSN: onu.SerialNumber,
1068 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001069 onu.sendOnuIndication(onuIndication, o.OpenoltStream)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001070
1071 }
1072
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001073 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001074}
1075
Shrey Baid688b4242020-07-10 20:40:10 +05301076func (o *OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001077 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001078 "IntfId": flow.AccessIntfId,
1079 "OnuId": flow.OnuId,
1080 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001081 "InnerVlan": flow.Classifier.IVid,
1082 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001083 "FlowType": flow.FlowType,
1084 "FlowId": flow.FlowId,
1085 "UniID": flow.UniId,
1086 "PortNo": flow.PortNo,
Pragya Arya8bdb4532020-03-02 17:08:09 +05301087 }).Tracef("OLT receives FlowAdd")
1088
Andrea Campanellacc9b1662022-01-26 17:47:48 +01001089 flowKey := FlowKey{}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301090 if !o.enablePerf {
yasin saplic07b9522022-01-27 11:23:54 +00001091 flowKey = FlowKey{ID: flow.FlowId}
Andrea Campanellacc9b1662022-01-26 17:47:48 +01001092 olt.Flows.Store(flowKey, *flow)
Pragya Arya8bdb4532020-03-02 17:08:09 +05301093 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001094
1095 if flow.AccessIntfId == -1 {
1096 oltLogger.WithFields(log.Fields{
1097 "FlowId": flow.FlowId,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001098 }).Debug("Adding OLT flow")
Jonathan Hartb5fc46a2020-03-31 16:42:31 -07001099 } else if flow.FlowType == "multicast" {
1100 oltLogger.WithFields(log.Fields{
Matteo Scandolo618a6582020-09-09 12:21:29 -07001101 "Cookie": flow.Cookie,
1102 "DstPort": flow.Classifier.DstPort,
1103 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
1104 "FlowId": flow.FlowId,
1105 "FlowType": flow.FlowType,
1106 "GemportId": flow.GemportId,
1107 "InnerVlan": flow.Classifier.IVid,
1108 "IntfId": flow.AccessIntfId,
1109 "IpProto": flow.Classifier.IpProto,
1110 "OnuId": flow.OnuId,
1111 "OuterVlan": flow.Classifier.OVid,
1112 "PortNo": flow.PortNo,
1113 "SrcPort": flow.Classifier.SrcPort,
1114 "UniID": flow.UniId,
1115 "ClassifierOPbits": flow.Classifier.OPbits,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001116 }).Debug("Adding OLT multicast flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001117 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001118 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -07001119 if err != nil {
1120 oltLogger.WithFields(log.Fields{
1121 "OnuId": flow.OnuId,
1122 "IntfId": flow.AccessIntfId,
1123 "err": err,
1124 }).Error("Can't find PonPort")
1125 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001126 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -07001127 if err != nil {
1128 oltLogger.WithFields(log.Fields{
1129 "OnuId": flow.OnuId,
1130 "IntfId": flow.AccessIntfId,
1131 "err": err,
1132 }).Error("Can't find Onu")
Jonathan Hartb5fc46a2020-03-31 16:42:31 -07001133 return nil, err
Matteo Scandolo27428702019-10-11 16:21:16 -07001134 }
Matteo Scandoloba3e9cd2021-05-14 16:19:54 -07001135
1136 // if the ONU is disabled reject the flow
1137 // as per VOL-4061 there is a small window during which the ONU is disabled
1138 // but the port has not been reported as down to ONOS
1139 if onu.InternalState.Is(OnuStatePonDisabled) || onu.InternalState.Is(OnuStateDisabled) {
1140 oltLogger.WithFields(log.Fields{
1141 "OnuId": flow.OnuId,
1142 "IntfId": flow.AccessIntfId,
1143 "Flow": flow,
1144 "SerialNumber": onu.Sn(),
1145 "InternalState": onu.InternalState.Current(),
1146 }).Error("rejected-flow-because-of-onu-state")
1147 return nil, fmt.Errorf("onu-%s-is-currently-%s", onu.Sn(), onu.InternalState.Current())
1148 }
1149
Pragya Arya8bdb4532020-03-02 17:08:09 +05301150 if !o.enablePerf {
Andrea Campanellacc9b1662022-01-26 17:47:48 +01001151 onu.Flows = append(onu.Flows, flowKey)
Pragya Arya1d5ffb82020-03-20 18:51:37 +05301152 // Generate event on first flow for ONU
Andrea Campanellacc9b1662022-01-26 17:47:48 +01001153 if len(onu.Flows) == 1 {
Matteo Scandoloba3e9cd2021-05-14 16:19:54 -07001154 publishEvent("Flow-add-received", int32(onu.PonPortID), int32(onu.ID), onu.Sn())
Pragya Arya1d5ffb82020-03-20 18:51:37 +05301155 }
Pragya Arya8bdb4532020-03-02 17:08:09 +05301156 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001157
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001158 // validate that the flow reference correct IDs (Alloc, Gem)
1159 if err := o.validateFlow(flow); err != nil {
1160 oltLogger.WithFields(log.Fields{
1161 "OnuId": flow.OnuId,
1162 "IntfId": flow.AccessIntfId,
1163 "Flow": flow,
1164 "SerialNumber": onu.Sn(),
1165 "err": err,
1166 }).Error("invalid-flow-for-onu")
1167 return nil, err
1168 }
1169
Matteo Scandoloa8eca492021-03-23 09:45:16 -07001170 o.storeGemPortIdByFlow(flow)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001171 o.storeAllocId(flow)
1172
Matteo Scandolof9d43412021-01-12 11:11:34 -08001173 msg := types.Message{
1174 Type: types.FlowAdd,
1175 Data: types.OnuFlowUpdateMessage{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001176 PonPortID: pon.ID,
1177 OnuID: onu.ID,
1178 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001179 },
1180 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001181 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001182 }
1183
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001184 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001185}
1186
Pragya Arya8bdb4532020-03-02 17:08:09 +05301187// FlowRemove request from VOLTHA
Shrey Baid688b4242020-07-10 20:40:10 +05301188func (o *OltDevice) FlowRemove(_ context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001189
Pragya Arya8bdb4532020-03-02 17:08:09 +05301190 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001191 "AllocId": flow.AllocId,
1192 "Cookie": flow.Cookie,
1193 "FlowId": flow.FlowId,
1194 "FlowType": flow.FlowType,
1195 "GemportId": flow.GemportId,
1196 "IntfId": flow.AccessIntfId,
1197 "OnuId": flow.OnuId,
1198 "PortNo": flow.PortNo,
1199 "UniID": flow.UniId,
1200 "ReplicateFlow": flow.ReplicateFlow,
1201 "PbitToGemport": flow.PbitToGemport,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001202 }).Debug("OLT receives FlowRemove")
Pragya Arya8bdb4532020-03-02 17:08:09 +05301203
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001204 olt.freeGemPortId(flow)
1205 olt.freeAllocId(flow)
1206
Pragya Arya8bdb4532020-03-02 17:08:09 +05301207 if !o.enablePerf { // remove only if flow were stored
yasin saplic07b9522022-01-27 11:23:54 +00001208 flowKey := FlowKey{ID: flow.FlowId}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301209 // Check if flow exists
Andrea Campanellacc9b1662022-01-26 17:47:48 +01001210 storedFlowIntf, ok := o.Flows.Load(flowKey)
Pragya Arya8bdb4532020-03-02 17:08:09 +05301211 if !ok {
1212 oltLogger.Errorf("Flow %v not found", flow)
1213 return new(openolt.Empty), status.Errorf(codes.NotFound, "Flow not found")
1214 }
1215
Andrea Campanellabe8e12f2020-12-14 18:43:41 +01001216 storedFlow := storedFlowIntf.(openolt.Flow)
1217
Pragya Arya8bdb4532020-03-02 17:08:09 +05301218 // if its ONU flow remove it from ONU also
1219 if storedFlow.AccessIntfId != -1 {
Matteo Scandolocedde462021-03-09 17:37:16 -08001220 pon, err := o.GetPonById(uint32(storedFlow.AccessIntfId))
1221 if err != nil {
1222 oltLogger.WithFields(log.Fields{
1223 "OnuId": storedFlow.OnuId,
1224 "IntfId": storedFlow.AccessIntfId,
1225 "PONs": olt.Pons,
1226 "err": err,
1227 }).Error("PON-port-not-found")
1228 return new(openolt.Empty), nil
1229 }
Pragya Arya8bdb4532020-03-02 17:08:09 +05301230 onu, err := pon.GetOnuById(uint32(storedFlow.OnuId))
1231 if err != nil {
1232 oltLogger.WithFields(log.Fields{
1233 "OnuId": storedFlow.OnuId,
1234 "IntfId": storedFlow.AccessIntfId,
1235 "err": err,
Matteo Scandolocedde462021-03-09 17:37:16 -08001236 }).Error("ONU-not-found")
Pragya Arya8bdb4532020-03-02 17:08:09 +05301237 return new(openolt.Empty), nil
1238 }
Andrea Campanellacc9b1662022-01-26 17:47:48 +01001239 onu.DeleteFlow(flowKey)
Matteo Scandoloba3e9cd2021-05-14 16:19:54 -07001240 publishEvent("Flow-remove-received", int32(onu.PonPortID), int32(onu.ID), onu.Sn())
Pragya Arya8bdb4532020-03-02 17:08:09 +05301241 }
1242
1243 // delete from olt flows
Andrea Campanellacc9b1662022-01-26 17:47:48 +01001244 o.Flows.Delete(flowKey)
Pragya Arya8bdb4532020-03-02 17:08:09 +05301245 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001246
1247 if flow.AccessIntfId == -1 {
1248 oltLogger.WithFields(log.Fields{
1249 "FlowId": flow.FlowId,
1250 }).Debug("Removing OLT flow")
1251 } else if flow.FlowType == "multicast" {
1252 oltLogger.WithFields(log.Fields{
1253 "FlowId": flow.FlowId,
1254 }).Debug("Removing OLT multicast flow")
1255 } else {
1256
1257 onu, err := o.GetOnuByFlowId(flow.FlowId)
1258 if err != nil {
1259 oltLogger.WithFields(log.Fields{
1260 "OnuId": flow.OnuId,
1261 "IntfId": flow.AccessIntfId,
1262 "err": err,
1263 }).Error("Can't find Onu")
1264 return nil, err
1265 }
1266
Matteo Scandolof9d43412021-01-12 11:11:34 -08001267 msg := types.Message{
1268 Type: types.FlowRemoved,
1269 Data: types.OnuFlowUpdateMessage{
Shrey Baid55f328c2020-07-07 19:20:42 +05301270 Flow: flow,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001271 },
1272 }
1273 onu.Channel <- msg
1274 }
1275
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001276 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001277}
1278
Shrey Baid688b4242020-07-10 20:40:10 +05301279func (o *OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo18859852020-01-15 13:33:57 -08001280 res := openolt.Heartbeat{HeartbeatSignature: uint32(time.Now().Unix())}
1281 oltLogger.WithFields(log.Fields{
1282 "signature": res.HeartbeatSignature,
1283 }).Trace("HeartbeatCheck")
1284 return &res, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001285}
1286
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001287func (o *OltDevice) GetOnuByFlowId(flowId uint64) (*Onu, error) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001288 for _, pon := range o.Pons {
1289 for _, onu := range pon.Onus {
1290 for _, fId := range onu.FlowIds {
1291 if fId == flowId {
1292 return onu, nil
1293 }
1294 }
1295 }
1296 }
Shrey Baid688b4242020-07-10 20:40:10 +05301297 return nil, fmt.Errorf("Cannot find Onu by flowId %d", flowId)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001298}
1299
Shrey Baid688b4242020-07-10 20:40:10 +05301300func (o *OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolocedde462021-03-09 17:37:16 -08001301 devinfo := &openolt.DeviceInfo{
1302 Vendor: common.Config.Olt.Vendor,
1303 Model: common.Config.Olt.Model,
1304 HardwareVersion: common.Config.Olt.HardwareVersion,
1305 FirmwareVersion: common.Config.Olt.FirmwareVersion,
Matteo Scandolocedde462021-03-09 17:37:16 -08001306 PonPorts: uint32(o.NumPon),
Matteo Scandolocedde462021-03-09 17:37:16 -08001307 DeviceSerialNumber: o.SerialNumber,
1308 DeviceId: common.Config.Olt.DeviceId,
1309 PreviouslyConnected: o.PreviouslyConnected,
Elia Battistonb7bea222022-02-18 16:25:00 +01001310 Ranges: []*openolt.DeviceInfo_DeviceResourceRanges{},
1311 }
1312
1313 for _, resRange := range common.PonsConfig.Ranges {
1314 intfIDs := []uint32{}
1315 for i := resRange.PonRange.StartId; i <= resRange.PonRange.EndId; i++ {
1316 intfIDs = append(intfIDs, uint32(i))
1317 }
1318
1319 devinfo.Ranges = append(devinfo.Ranges, &openolt.DeviceInfo_DeviceResourceRanges{
1320 IntfIds: intfIDs,
1321 Technology: resRange.Technology,
1322 Pools: []*openolt.DeviceInfo_DeviceResourceRanges_Pool{
1323 {
1324 Type: openolt.DeviceInfo_DeviceResourceRanges_Pool_ONU_ID,
1325 Sharing: openolt.DeviceInfo_DeviceResourceRanges_Pool_DEDICATED_PER_INTF,
1326 Start: resRange.OnuRange.StartId,
1327 End: resRange.OnuRange.EndId,
1328 },
1329 {
1330 Type: openolt.DeviceInfo_DeviceResourceRanges_Pool_ALLOC_ID,
1331 Sharing: openolt.DeviceInfo_DeviceResourceRanges_Pool_DEDICATED_PER_INTF,
1332 Start: resRange.AllocIdRange.StartId,
1333 End: resRange.AllocIdRange.EndId,
1334 },
1335 {
1336 Type: openolt.DeviceInfo_DeviceResourceRanges_Pool_GEMPORT_ID,
1337 Sharing: openolt.DeviceInfo_DeviceResourceRanges_Pool_DEDICATED_PER_INTF,
1338 Start: resRange.GemportRange.StartId,
1339 End: resRange.GemportRange.EndId,
Matteo Scandolocedde462021-03-09 17:37:16 -08001340 },
1341 },
Elia Battistonb7bea222022-02-18 16:25:00 +01001342 })
Matteo Scandolocedde462021-03-09 17:37:16 -08001343 }
Matteo Scandolo96f89192021-03-12 13:17:26 -08001344
1345 oltLogger.WithFields(log.Fields{
1346 "Vendor": devinfo.Vendor,
1347 "Model": devinfo.Model,
1348 "HardwareVersion": devinfo.HardwareVersion,
1349 "FirmwareVersion": devinfo.FirmwareVersion,
Matteo Scandolo96f89192021-03-12 13:17:26 -08001350 "PonPorts": devinfo.PonPorts,
Matteo Scandolo96f89192021-03-12 13:17:26 -08001351 "DeviceSerialNumber": devinfo.DeviceSerialNumber,
1352 "DeviceId": devinfo.DeviceId,
1353 "PreviouslyConnected": devinfo.PreviouslyConnected,
1354 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
1355
1356 // once we connect, set the flag
1357 o.PreviouslyConnected = true
Matteo Scandolo4747d292019-08-05 11:50:18 -07001358
1359 return devinfo, nil
1360}
1361
Shrey Baid688b4242020-07-10 20:40:10 +05301362func (o *OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Jonathan Hartacfa20e2020-03-31 15:20:14 -07001363 pon, err := o.GetPonById(omci_msg.IntfId)
1364 if err != nil {
1365 oltLogger.WithFields(log.Fields{
Matteo Scandolof65e6872020-04-15 15:18:43 -07001366 "error": err,
Jonathan Hartacfa20e2020-03-31 15:20:14 -07001367 "onu_id": omci_msg.OnuId,
1368 "pon_id": omci_msg.IntfId,
1369 }).Error("pon ID not found")
1370 return nil, err
1371 }
1372
1373 onu, err := pon.GetOnuById(omci_msg.OnuId)
1374 if err != nil {
1375 oltLogger.WithFields(log.Fields{
Matteo Scandolof65e6872020-04-15 15:18:43 -07001376 "error": err,
Jonathan Hartacfa20e2020-03-31 15:20:14 -07001377 "onu_id": omci_msg.OnuId,
1378 "pon_id": omci_msg.IntfId,
1379 }).Error("onu ID not found")
1380 return nil, err
1381 }
1382
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001383 oltLogger.WithFields(log.Fields{
1384 "IntfId": onu.PonPortID,
1385 "OnuId": onu.ID,
1386 "OnuSn": onu.Sn(),
1387 }).Tracef("Received OmciMsgOut")
Matteo Scandolob5913142021-03-19 16:10:18 -07001388 omciPkt, omciMsg, err := omcilib.ParseOpenOltOmciPacket(omci_msg.Pkt)
1389 if err != nil {
1390 log.WithFields(log.Fields{
1391 "IntfId": onu.PonPortID,
1392 "SerialNumber": onu.Sn(),
1393 "omciPacket": omcilib.HexDecode(omci_msg.Pkt),
1394 "err": err.Error(),
1395 }).Error("cannot-parse-OMCI-packet")
1396 return nil, fmt.Errorf("olt-received-malformed-omci-packet")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001397 }
Matteo Scandolob5913142021-03-19 16:10:18 -07001398 if onu.InternalState.Current() == OnuStateDisabled {
1399 // if the ONU is disabled just drop the message
1400 log.WithFields(log.Fields{
1401 "IntfId": onu.PonPortID,
1402 "SerialNumber": onu.Sn(),
1403 "omciBytes": hex.EncodeToString(omciPkt.Data()),
1404 "omciPkt": omciPkt,
1405 "omciMsgType": omciMsg.MessageType,
1406 }).Warn("dropping-omci-message")
1407 } else {
1408 msg := types.Message{
1409 Type: types.OMCI,
1410 Data: types.OmciMessage{
1411 OnuSN: onu.SerialNumber,
1412 OnuID: onu.ID,
1413 OmciMsg: omciMsg,
1414 OmciPkt: omciPkt,
1415 },
1416 }
1417 onu.Channel <- msg
1418 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001419 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001420}
1421
Matteo Scandolo8a574812021-05-20 15:18:53 -07001422// this gRPC methods receives packets from VOLTHA and sends them to the subscriber on the ONU
Shrey Baid688b4242020-07-10 20:40:10 +05301423func (o *OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001424 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -07001425 if err != nil {
1426 oltLogger.WithFields(log.Fields{
1427 "OnuId": onuPkt.OnuId,
1428 "IntfId": onuPkt.IntfId,
1429 "err": err,
1430 }).Error("Can't find PonPort")
1431 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001432 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -07001433 if err != nil {
1434 oltLogger.WithFields(log.Fields{
1435 "OnuId": onuPkt.OnuId,
1436 "IntfId": onuPkt.IntfId,
1437 "err": err,
1438 }).Error("Can't find Onu")
1439 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001440
Matteo Scandolo075b1892019-10-07 12:11:07 -07001441 oltLogger.WithFields(log.Fields{
1442 "IntfId": onu.PonPortID,
1443 "OnuId": onu.ID,
1444 "OnuSn": onu.Sn(),
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001445 "Packet": hex.EncodeToString(onuPkt.Pkt),
Matteo Scandolo75ed5b92020-09-03 09:03:16 -07001446 }).Trace("Received OnuPacketOut")
Matteo Scandolo075b1892019-10-07 12:11:07 -07001447
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001448 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo618a6582020-09-09 12:21:29 -07001449
1450 pktType, err := packetHandlers.GetPktType(rawpkt)
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001451 if err != nil {
1452 onuLogger.WithFields(log.Fields{
1453 "IntfId": onu.PonPortID,
1454 "OnuId": onu.ID,
1455 "OnuSn": onu.Sn(),
Matteo Scandolo618a6582020-09-09 12:21:29 -07001456 "Pkt": hex.EncodeToString(rawpkt.Data()),
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001457 }).Error("Can't find pktType in packet, droppint it")
1458 return new(openolt.Empty), nil
1459 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001460
Matteo Scandolo4a036262020-08-17 15:56:13 -07001461 pktMac, err := packetHandlers.GetDstMacAddressFromPacket(rawpkt)
Matteo Scandolo4a036262020-08-17 15:56:13 -07001462 if err != nil {
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001463 onuLogger.WithFields(log.Fields{
Matteo Scandolo4a036262020-08-17 15:56:13 -07001464 "IntfId": onu.PonPortID,
1465 "OnuId": onu.ID,
1466 "OnuSn": onu.Sn(),
1467 "Pkt": rawpkt.Data(),
1468 }).Error("Can't find Dst MacAddress in packet, droppint it")
1469 return new(openolt.Empty), nil
1470 }
1471
Matteo Scandolof9d43412021-01-12 11:11:34 -08001472 msg := types.Message{
1473 Type: types.OnuPacketOut,
1474 Data: types.OnuPacketMessage{
Matteo Scandolo4a036262020-08-17 15:56:13 -07001475 IntfId: onuPkt.IntfId,
1476 OnuId: onuPkt.OnuId,
Matteo Scandolo8a574812021-05-20 15:18:53 -07001477 PortNo: onuPkt.PortNo,
Matteo Scandolo4a036262020-08-17 15:56:13 -07001478 Packet: rawpkt,
1479 Type: pktType,
1480 MacAddress: pktMac,
Matteo Scandolo075b1892019-10-07 12:11:07 -07001481 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001482 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001483
Matteo Scandolo075b1892019-10-07 12:11:07 -07001484 onu.Channel <- msg
1485
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001486 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001487}
1488
Shrey Baid688b4242020-07-10 20:40:10 +05301489func (o *OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo635b2bf2020-09-04 10:23:40 -07001490
1491 // OLT Reboot is called in two cases:
1492 // - when an OLT is being removed (voltctl device disable -> voltctl device delete are called, then a new voltctl device create -> voltctl device enable will be issued)
1493 // - when an OLT needs to be rebooted (voltcl device reboot)
1494
Matteo Scandolod02b79b2019-12-05 16:42:13 -08001495 oltLogger.WithFields(log.Fields{
1496 "oltId": o.ID,
1497 }).Info("Shutting down")
Pragya Arya324337e2020-02-20 14:35:08 +05301498 publishEvent("OLT-reboot-received", -1, -1, "")
Shrey Baid688b4242020-07-10 20:40:10 +05301499 go func() { _ = o.RestartOLT() }()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001500 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001501}
1502
Shrey Baid688b4242020-07-10 20:40:10 +05301503func (o *OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Pragya Arya6a708d62020-01-01 17:17:20 +05301504 oltLogger.WithFields(log.Fields{
1505 "oltId": o.ID,
1506 }).Info("Received ReenableOlt request from VOLTHA")
Pragya Arya324337e2020-02-20 14:35:08 +05301507 publishEvent("OLT-reenable-received", -1, -1, "")
Pragya Arya6a708d62020-01-01 17:17:20 +05301508
Pragya Arya2225f202020-01-29 18:05:01 +05301509 // enable OLT
Matteo Scandolof9d43412021-01-12 11:11:34 -08001510 oltMsg := types.Message{
1511 Type: types.OltIndication,
1512 Data: types.OltIndicationMessage{
1513 OperState: types.UP,
Pragya Arya2225f202020-01-29 18:05:01 +05301514 },
Pragya Arya1881df02020-01-29 18:05:01 +05301515 }
Pragya Arya2225f202020-01-29 18:05:01 +05301516 o.channel <- oltMsg
Pragya Arya6a708d62020-01-01 17:17:20 +05301517
Pragya Arya2225f202020-01-29 18:05:01 +05301518 for _, pon := range o.Pons {
1519 if pon.InternalState.Current() == "disabled" {
Matteo Scandolof9d43412021-01-12 11:11:34 -08001520 msg := types.Message{
1521 Type: types.PonIndication,
1522 Data: types.PonIndicationMessage{
1523 OperState: types.UP,
Pragya Arya2225f202020-01-29 18:05:01 +05301524 PonPortID: pon.ID,
1525 },
1526 }
1527 o.channel <- msg
1528 }
1529 }
Matteo Scandoloe60a5052020-02-07 00:31:14 +00001530
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001531 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001532}
1533
Shrey Baid688b4242020-07-10 20:40:10 +05301534func (o *OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001535 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
1536
Matteo Scandolo90d08f62020-10-29 12:06:55 -07001537 err := o.Nnis[0].handleNniPacket(pkt) // FIXME we are assuming we have only one NNI
1538
1539 if err != nil {
1540 return nil, err
1541 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001542 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001543}
1544
Shrey Baid688b4242020-07-10 20:40:10 +05301545func (o *OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001546 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001547 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001548}
1549
Shrey Baid688b4242020-07-10 20:40:10 +05301550func (o *OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001551 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001552 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001553}
1554
Shrey Baid688b4242020-07-10 20:40:10 +05301555func (o *OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001556 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001557 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -07001558}
1559
Shrey Baid688b4242020-07-10 20:40:10 +05301560func (s *OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001561 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001562 return new(openolt.Empty), nil
1563}
1564
Matteo Scandolo8a574812021-05-20 15:18:53 -07001565func (s *OltDevice) RemoveTrafficQueues(_ context.Context, tq *tech_profile.TrafficQueues) (*openolt.Empty, error) {
1566 oltLogger.WithFields(log.Fields{
1567 "OnuId": tq.OnuId,
1568 "IntfId": tq.IntfId,
1569 "OnuPortNo": tq.PortNo,
1570 "UniId": tq.UniId,
1571 }).Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001572 return new(openolt.Empty), nil
1573}
1574
Matteo Scandolo8a574812021-05-20 15:18:53 -07001575func (s *OltDevice) CreateTrafficSchedulers(_ context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Anand S Katti09541352020-01-29 15:54:01 +05301576 oltLogger.WithFields(log.Fields{
1577 "OnuId": trafficSchedulers.OnuId,
1578 "IntfId": trafficSchedulers.IntfId,
1579 "OnuPortNo": trafficSchedulers.PortNo,
Matteo Scandolo8a574812021-05-20 15:18:53 -07001580 "UniId": trafficSchedulers.UniId,
Anand S Katti09541352020-01-29 15:54:01 +05301581 }).Info("received CreateTrafficSchedulers")
1582
1583 if !s.enablePerf {
1584 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1585 if err != nil {
1586 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1587 return new(openolt.Empty), err
1588 }
1589 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1590 if err != nil {
1591 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1592 return new(openolt.Empty), err
1593 }
1594 onu.TrafficSchedulers = trafficSchedulers
1595 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001596 return new(openolt.Empty), nil
1597}
1598
Shrey Baid688b4242020-07-10 20:40:10 +05301599func (s *OltDevice) RemoveTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Anand S Katti09541352020-01-29 15:54:01 +05301600 oltLogger.WithFields(log.Fields{
1601 "OnuId": trafficSchedulers.OnuId,
1602 "IntfId": trafficSchedulers.IntfId,
1603 "OnuPortNo": trafficSchedulers.PortNo,
1604 }).Info("received RemoveTrafficSchedulers")
1605 if !s.enablePerf {
1606 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1607 if err != nil {
1608 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1609 return new(openolt.Empty), err
1610 }
1611 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1612 if err != nil {
1613 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1614 return new(openolt.Empty), err
1615 }
1616
1617 onu.TrafficSchedulers = nil
1618 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001619 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001620}
Scott Baker41724b82020-01-21 19:54:53 -08001621
Matteo Scandolo618a6582020-09-09 12:21:29 -07001622func (o *OltDevice) PerformGroupOperation(ctx context.Context, group *openolt.Group) (*openolt.Empty, error) {
1623 oltLogger.WithFields(log.Fields{
1624 "GroupId": group.GroupId,
1625 "Command": group.Command,
1626 "Members": group.Members,
1627 "Action": group.Action,
1628 }).Debug("received PerformGroupOperation")
1629 return &openolt.Empty{}, nil
1630}
1631
1632func (o *OltDevice) DeleteGroup(ctx context.Context, group *openolt.Group) (*openolt.Empty, error) {
1633 oltLogger.WithFields(log.Fields{
1634 "GroupId": group.GroupId,
1635 "Command": group.Command,
1636 "Members": group.Members,
1637 "Action": group.Action,
1638 }).Debug("received PerformGroupOperation")
1639 return &openolt.Empty{}, nil
1640}
1641
Matteo Scandolo1f9f4b22021-12-14 11:51:55 -08001642func (o *OltDevice) GetExtValue(ctx context.Context, in *openolt.ValueParam) (*extension.ReturnValues, error) {
1643 return &extension.ReturnValues{}, nil
Matteo Scandolo618a6582020-09-09 12:21:29 -07001644}
1645
1646func (o *OltDevice) OnuItuPonAlarmSet(ctx context.Context, in *config.OnuItuPonAlarm) (*openolt.Empty, error) {
1647 return &openolt.Empty{}, nil
1648}
1649
1650func (o *OltDevice) GetLogicalOnuDistanceZero(ctx context.Context, in *openolt.Onu) (*openolt.OnuLogicalDistance, error) {
1651 return &openolt.OnuLogicalDistance{}, nil
1652}
1653
1654func (o *OltDevice) GetLogicalOnuDistance(ctx context.Context, in *openolt.Onu) (*openolt.OnuLogicalDistance, error) {
1655 return &openolt.OnuLogicalDistance{}, nil
1656}
Matteo Scandolo96f89192021-03-12 13:17:26 -08001657
Girish Gowdra62f24292021-05-12 16:28:39 -07001658func (o *OltDevice) GetPonRxPower(ctx context.Context, in *openolt.Onu) (*openolt.PonRxPowerData, error) {
1659 return &openolt.PonRxPowerData{}, nil
1660}
1661
Matteo Scandolo96f89192021-03-12 13:17:26 -08001662func (o *OltDevice) GetGemPortStatistics(ctx context.Context, in *openolt.OnuPacket) (*openolt.GemPortStatistics, error) {
1663 return &openolt.GemPortStatistics{}, nil
1664}
1665
1666func (o *OltDevice) GetOnuStatistics(ctx context.Context, in *openolt.Onu) (*openolt.OnuStatistics, error) {
1667 return &openolt.OnuStatistics{}, nil
1668}
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001669
1670func (o *OltDevice) storeAllocId(flow *openolt.Flow) {
1671 o.AllocIDsLock.Lock()
1672 defer o.AllocIDsLock.Unlock()
1673
Matteo Scandolo21195d62021-04-07 14:31:23 -07001674 if _, ok := o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)]; !ok {
1675 oltLogger.WithFields(log.Fields{
1676 "IntfId": flow.AccessIntfId,
1677 "OnuId": flow.OnuId,
1678 "PortNo": flow.PortNo,
1679 "GemportId": flow.GemportId,
1680 "FlowId": flow.FlowId,
1681 }).Error("trying-to-store-alloc-id-for-unknown-onu")
1682 }
1683
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001684 oltLogger.WithFields(log.Fields{
Matteo Scandolo21195d62021-04-07 14:31:23 -07001685 "IntfId": flow.AccessIntfId,
1686 "OnuId": flow.OnuId,
1687 "PortNo": flow.PortNo,
1688 "GemportId": flow.GemportId,
1689 "FlowId": flow.FlowId,
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001690 }).Trace("storing-alloc-id-via-flow")
1691
1692 if _, ok := o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo]; !ok {
1693 o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo] = make(map[int32]map[uint64]bool)
1694 }
1695 if _, ok := o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.AllocId]; !ok {
1696 o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.AllocId] = make(map[uint64]bool)
1697 }
1698 o.AllocIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.AllocId][flow.FlowId] = true
1699}
1700
1701func (o *OltDevice) freeAllocId(flow *openolt.Flow) {
1702 // if this is the last flow referencing the AllocId then remove it
1703 o.AllocIDsLock.Lock()
1704 defer o.AllocIDsLock.Unlock()
1705
1706 oltLogger.WithFields(log.Fields{
1707 "IntfId": flow.AccessIntfId,
1708 "OnuId": flow.OnuId,
1709 "PortNo": flow.PortNo,
1710 "GemportId": flow.GemportId,
1711 }).Trace("freeing-alloc-id-via-flow")
1712
1713 // NOTE look at the freeGemPortId implementation for comments and context
1714 for ponId, ponValues := range o.AllocIDs {
1715 for onuId, onuValues := range ponValues {
1716 for uniId, uniValues := range onuValues {
1717 for allocId, flows := range uniValues {
1718 for flowId := range flows {
1719 // if the flow matches, remove it from the map.
1720 if flow.FlowId == flowId {
1721 delete(o.AllocIDs[ponId][onuId][uniId][allocId], flow.FlowId)
1722 }
1723 // if that was the last flow for a particular allocId, remove the entire allocId
1724 if len(o.AllocIDs[ponId][onuId][uniId][allocId]) == 0 {
1725 delete(o.AllocIDs[ponId][onuId][uniId], allocId)
1726 }
1727 }
1728 }
1729 }
1730 }
1731 }
1732}
1733
Matteo Scandoloa8eca492021-03-23 09:45:16 -07001734func (o *OltDevice) storeGemPortId(ponId uint32, onuId uint32, portNo uint32, gemId int32, flowId uint64) {
Matteo Scandolo21195d62021-04-07 14:31:23 -07001735 o.GemPortIDsLock.Lock()
1736 defer o.GemPortIDsLock.Unlock()
1737
1738 if _, ok := o.GemPortIDs[ponId][onuId]; !ok {
1739 oltLogger.WithFields(log.Fields{
1740 "IntfId": ponId,
1741 "OnuId": onuId,
1742 "PortNo": portNo,
1743 "GemportId": gemId,
1744 "FlowId": flowId,
1745 }).Error("trying-to-store-gemport-for-unknown-onu")
1746 }
1747
1748 oltLogger.WithFields(log.Fields{
1749 "IntfId": ponId,
1750 "OnuId": onuId,
1751 "PortNo": portNo,
1752 "GemportId": gemId,
1753 "FlowId": flowId,
1754 }).Trace("storing-alloc-id-via-flow")
1755
Matteo Scandoloa8eca492021-03-23 09:45:16 -07001756 if _, ok := o.GemPortIDs[ponId][onuId][portNo]; !ok {
1757 o.GemPortIDs[ponId][onuId][portNo] = make(map[int32]map[uint64]bool)
1758 }
1759 if _, ok := o.GemPortIDs[ponId][onuId][portNo][gemId]; !ok {
1760 o.GemPortIDs[ponId][onuId][portNo][gemId] = make(map[uint64]bool)
1761 }
1762 o.GemPortIDs[ponId][onuId][portNo][gemId][flowId] = true
1763}
1764
1765func (o *OltDevice) storeGemPortIdByFlow(flow *openolt.Flow) {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001766 oltLogger.WithFields(log.Fields{
Matteo Scandolo21195d62021-04-07 14:31:23 -07001767 "IntfId": flow.AccessIntfId,
1768 "OnuId": flow.OnuId,
1769 "PortNo": flow.PortNo,
1770 "GemportId": flow.GemportId,
1771 "FlowId": flow.FlowId,
1772 "ReplicateFlow": flow.ReplicateFlow,
1773 "PbitToGemport": flow.PbitToGemport,
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001774 }).Trace("storing-gem-port-id-via-flow")
1775
Matteo Scandoloa8eca492021-03-23 09:45:16 -07001776 if flow.ReplicateFlow {
1777 for _, gem := range flow.PbitToGemport {
1778 o.storeGemPortId(uint32(flow.AccessIntfId), uint32(flow.OnuId), flow.PortNo, int32(gem), flow.FlowId)
1779 }
1780 } else {
1781 o.storeGemPortId(uint32(flow.AccessIntfId), uint32(flow.OnuId), flow.PortNo, flow.GemportId, flow.FlowId)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001782 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001783}
1784
1785func (o *OltDevice) freeGemPortId(flow *openolt.Flow) {
1786 // if this is the last flow referencing the GemPort then remove it
1787 o.GemPortIDsLock.Lock()
1788 defer o.GemPortIDsLock.Unlock()
1789
1790 oltLogger.WithFields(log.Fields{
1791 "IntfId": flow.AccessIntfId,
1792 "OnuId": flow.OnuId,
1793 "PortNo": flow.PortNo,
1794 "GemportId": flow.GemportId,
1795 }).Trace("freeing-gem-port-id-via-flow")
1796
1797 // NOTE that this loop is not very performant, it would be better if the flow carries
1798 // the same information that it carries during a FlowAdd. If so we can directly remove
1799 // items from the map
1800
1801 //delete(o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.GemportId], flow.FlowId)
1802 //if len(o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo][flow.GemportId]) == 0 {
1803 // delete(o.GemPortIDs[uint32(flow.AccessIntfId)][uint32(flow.OnuId)][flow.PortNo], flow.GemportId)
1804 //}
1805
1806 // NOTE this loop assumes that flow IDs are unique per device
1807 for ponId, ponValues := range o.GemPortIDs {
1808 for onuId, onuValues := range ponValues {
1809 for uniId, uniValues := range onuValues {
1810 for gemId, flows := range uniValues {
1811 for flowId := range flows {
1812 // if the flow matches, remove it from the map.
1813 if flow.FlowId == flowId {
1814 delete(o.GemPortIDs[ponId][onuId][uniId][gemId], flow.FlowId)
1815 }
1816 // if that was the last flow for a particular gem, remove the entire gem
1817 if len(o.GemPortIDs[ponId][onuId][uniId][gemId]) == 0 {
1818 delete(o.GemPortIDs[ponId][onuId][uniId], gemId)
1819 }
1820 }
1821 }
1822 }
1823 }
1824 }
1825}
1826
1827// validateFlow checks that:
1828// - the AllocId is not used in any flow referencing other ONUs/UNIs on the same PON
1829// - the GemPortId is not used in any flow referencing other ONUs/UNIs on the same PON
1830func (o *OltDevice) validateFlow(flow *openolt.Flow) error {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001831 // validate gemPort
1832 o.GemPortIDsLock.RLock()
Matteo Scandolo21195d62021-04-07 14:31:23 -07001833 defer o.GemPortIDsLock.RUnlock()
1834 for onuId, onu := range o.GemPortIDs[uint32(flow.AccessIntfId)] {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001835 if onuId == uint32(flow.OnuId) {
1836 continue
1837 }
1838 for uniId, uni := range onu {
1839 for gem := range uni {
Matteo Scandoloa8eca492021-03-23 09:45:16 -07001840 if flow.ReplicateFlow {
1841 for _, flowGem := range flow.PbitToGemport {
1842 if gem == int32(flowGem) {
1843 return fmt.Errorf("gem-%d-already-in-use-on-uni-%d-onu-%d-replicated-flow-%d", gem, uniId, onuId, flow.FlowId)
1844 }
1845 }
1846 } else {
1847 if gem == flow.GemportId {
1848 return fmt.Errorf("gem-%d-already-in-use-on-uni-%d-onu-%d-flow-%d", gem, uniId, onuId, flow.FlowId)
1849 }
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001850 }
1851 }
1852 }
1853 }
1854
1855 o.AllocIDsLock.RLock()
Matteo Scandolo21195d62021-04-07 14:31:23 -07001856 defer o.AllocIDsLock.RUnlock()
1857 for onuId, onu := range o.AllocIDs[uint32(flow.AccessIntfId)] {
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001858 if onuId == uint32(flow.OnuId) {
1859 continue
1860 }
1861 for uniId, uni := range onu {
1862 for allocId := range uni {
1863 if allocId == flow.AllocId {
Matteo Scandoloa8eca492021-03-23 09:45:16 -07001864 return fmt.Errorf("allocId-%d-already-in-use-on-uni-%d-onu-%d-flow-%d", allocId, uniId, onuId, flow.FlowId)
Matteo Scandolo4b077aa2021-02-16 17:33:37 -08001865 }
1866 }
1867 }
1868 }
1869
1870 return nil
1871}
1872
1873// clearAllResources is invoked up OLT Reboot to remove all the allocated
1874// GemPorts, AllocId and ONU-IDs across the PONs
1875func (o *OltDevice) clearAllResources() {
1876
1877 // remove the resources received via flows
1878 o.GemPortIDsLock.Lock()
1879 o.GemPortIDs = make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool)
1880 o.GemPortIDsLock.Unlock()
1881 o.AllocIDsLock.Lock()
1882 o.AllocIDs = make(map[uint32]map[uint32]map[uint32]map[int32]map[uint64]bool)
1883 o.AllocIDsLock.Unlock()
1884
1885 // remove the resources received via OMCI
1886 for _, pon := range o.Pons {
1887 pon.removeAllAllocIds()
1888 pon.removeAllGemPorts()
1889 pon.removeAllOnuIds()
1890 }
1891}