blob: c3e08669150a12936f078089d5d025fcefe90bfc [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"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070023 "github.com/opencord/voltha-protos/v4/go/ext/config"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020024 "net"
25 "sync"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010026 "time"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020027
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070028 "github.com/google/gopacket"
29 "github.com/google/gopacket/layers"
Matteo Scandolodf3f85d2020-01-15 12:50:48 -080030 "github.com/google/gopacket/pcap"
Matteo Scandolo4747d292019-08-05 11:50:18 -070031 "github.com/looplab/fsm"
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070032 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070033 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +010034 "github.com/opencord/bbsim/internal/common"
William Kurkian9dadc5b2019-10-22 13:51:57 -040035 omcisim "github.com/opencord/omci-sim"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070036 common_protos "github.com/opencord/voltha-protos/v4/go/common"
37 "github.com/opencord/voltha-protos/v4/go/openolt"
38 "github.com/opencord/voltha-protos/v4/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070039 log "github.com/sirupsen/logrus"
40 "google.golang.org/grpc"
Pragya Arya8bdb4532020-03-02 17:08:09 +053041 "google.golang.org/grpc/codes"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010042 "google.golang.org/grpc/reflection"
Pragya Arya8bdb4532020-03-02 17:08:09 +053043 "google.golang.org/grpc/status"
Matteo Scandolo4747d292019-08-05 11:50:18 -070044)
45
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070046var oltLogger = log.WithFields(log.Fields{
Matteo Scandolo84f7d482019-08-08 19:00:47 -070047 "module": "OLT",
48})
49
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070050type OltDevice struct {
David Bainbridge103cf022019-12-16 20:11:35 +000051 sync.Mutex
52
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070053 // BBSIM Internals
Pragya Arya2225f202020-01-29 18:05:01 +053054 ID int
55 SerialNumber string
56 NumNni int
57 NumPon int
58 NumOnuPerPon int
59 InternalState *fsm.FSM
60 channel chan Message
61 nniPktInChannel chan *bbsim.PacketMsg // packets coming in from the NNI and going to VOLTHA
62 nniHandle *pcap.Handle // handle on the NNI interface, close it when shutting down the NNI channel
Pragya Arya8bdb4532020-03-02 17:08:09 +053063 Flows map[FlowKey]openolt.Flow
Pragya Arya2225f202020-01-29 18:05:01 +053064 Delay int
65 ControlledActivation mode
Pragya Arya324337e2020-02-20 14:35:08 +053066 EventChannel chan common.Event
67 PublishEvents bool
Pragya Arya996a0892020-03-09 21:47:52 +053068 PortStatsInterval int
Matteo Scandoloe33447a2019-10-31 12:38:23 -070069
Matteo Scandolo27428702019-10-11 16:21:16 -070070 Pons []*PonPort
71 Nnis []*NniPort
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070072
73 // OLT Attributes
74 OperState *fsm.FSM
David Bainbridge103cf022019-12-16 20:11:35 +000075
76 enableContext context.Context
77 enableContextCancel context.CancelFunc
Pragya Arya1cbefa42020-01-13 12:15:29 +053078
Matteo Scandolo4a036262020-08-17 15:56:13 -070079 OpenoltStream openolt.Openolt_EnableIndicationServer
Anand S Katti09541352020-01-29 15:54:01 +053080 enablePerf bool
Matteo Scandolo4747d292019-08-05 11:50:18 -070081}
82
Matteo Scandolo27428702019-10-11 16:21:16 -070083var olt OltDevice
Zdravko Bozakov681364d2019-11-10 14:28:46 +010084var oltServer *grpc.Server
Matteo Scandolo84f7d482019-08-08 19:00:47 -070085
Matteo Scandolo27428702019-10-11 16:21:16 -070086func GetOLT() *OltDevice {
87 return &olt
Matteo Scandolo84f7d482019-08-08 19:00:47 -070088}
89
Matteo Scandolo4a036262020-08-17 15:56:13 -070090func CreateOLT(options common.GlobalConfig, services []common.ServiceYaml, isMock bool) *OltDevice {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070091 oltLogger.WithFields(log.Fields{
Pragya Arya996a0892020-03-09 21:47:52 +053092 "ID": options.Olt.ID,
93 "NumNni": options.Olt.NniPorts,
94 "NumPon": options.Olt.PonPorts,
95 "NumOnuPerPon": options.Olt.OnusPonPort,
Matteo Scandolo4747d292019-08-05 11:50:18 -070096 }).Debug("CreateOLT")
97
Matteo Scandolo84f7d482019-08-08 19:00:47 -070098 olt = OltDevice{
Pragya Arya996a0892020-03-09 21:47:52 +053099 ID: options.Olt.ID,
100 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", options.Olt.ID),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700101 OperState: getOperStateFSM(func(e *fsm.Event) {
102 oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
103 }),
Pragya Arya996a0892020-03-09 21:47:52 +0530104 NumNni: int(options.Olt.NniPorts),
105 NumPon: int(options.Olt.PonPorts),
106 NumOnuPerPon: int(options.Olt.OnusPonPort),
107 Pons: []*PonPort{},
108 Nnis: []*NniPort{},
109 Delay: options.BBSim.Delay,
110 Flows: make(map[FlowKey]openolt.Flow),
111 enablePerf: options.BBSim.EnablePerf,
112 PublishEvents: options.BBSim.Events,
113 PortStatsInterval: options.Olt.PortStatsInterval,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700114 }
115
Pragya Arya996a0892020-03-09 21:47:52 +0530116 if val, ok := ControlledActivationModes[options.BBSim.ControlledActivation]; ok {
Pragya Arya2225f202020-01-29 18:05:01 +0530117 olt.ControlledActivation = val
118 } else {
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700119 // FIXME throw an error if the ControlledActivation is not valid
Pragya Arya2225f202020-01-29 18:05:01 +0530120 oltLogger.Warn("Unknown ControlledActivation Mode given, running in Default mode")
121 olt.ControlledActivation = Default
122 }
123
Matteo Scandolo4747d292019-08-05 11:50:18 -0700124 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700125 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700126 olt.InternalState = fsm.NewFSM(
127 "created",
128 fsm.Events{
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800129 {Name: "initialize", Src: []string{"created", "deleted"}, Dst: "initialized"},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100130 {Name: "enable", Src: []string{"initialized", "disabled"}, Dst: "enabled"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700131 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700132 // delete event in enabled state below is for reboot OLT case.
Mahir Gunyel6dad4452020-01-06 12:59:04 -0800133 {Name: "delete", Src: []string{"disabled", "enabled"}, Dst: "deleted"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700134 },
135 fsm.Callbacks{
136 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700137 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700138 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100139 "enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
Matteo Scandolo4747d292019-08-05 11:50:18 -0700140 },
141 )
142
Shrey Baid688b4242020-07-10 20:40:10 +0530143 if !isMock {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700144 // create NNI Port
145 nniPort, err := CreateNNI(&olt)
146 if err != nil {
147 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
148 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700149
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700150 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700151 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700152
Matteo Scandolo4a036262020-08-17 15:56:13 -0700153 // Create device and Services
154
155 nextCtag := map[string]int{}
156 nextStag := map[string]int{}
157
Matteo Scandolo4747d292019-08-05 11:50:18 -0700158 // create PON ports
Matteo Scandolo4a036262020-08-17 15:56:13 -0700159 for i := 0; i < olt.NumPon; i++ {
160 p := CreatePonPort(&olt, uint32(i))
Matteo Scandolo4747d292019-08-05 11:50:18 -0700161
Matteo Scandolo4a036262020-08-17 15:56:13 -0700162 // create ONU devices
163 for j := 0; j < olt.NumOnuPerPon; j++ {
164 delay := time.Duration(olt.Delay*j) * time.Millisecond
165 o := CreateONU(&olt, p, uint32(j+1), delay, isMock)
Matteo Scandolof65e6872020-04-15 15:18:43 -0700166
Matteo Scandolo4a036262020-08-17 15:56:13 -0700167 for k, s := range common.Services {
168
169 // find the correct cTag for this service
170 if _, ok := nextCtag[s.Name]; !ok {
171 // it's the first time we iterate over this service,
172 // so we start from the config value
173 nextCtag[s.Name] = s.CTag
174 } else {
175 // we have a previous value, so we check it
176 // if Allocation is unique, we increment,
177 // otherwise (shared) we do nothing
178 if s.CTagAllocation == common.TagAllocationUnique.String() {
179 nextCtag[s.Name] = nextCtag[s.Name] + 1
180 }
181 }
182
183 // find the correct sTag for this service
184 if _, ok := nextStag[s.Name]; !ok {
185 nextStag[s.Name] = s.STag
186 } else {
187 if s.STagAllocation == common.TagAllocationUnique.String() {
188 nextStag[s.Name] = nextStag[s.Name] + 1
189 }
190 }
191
192 mac := net.HardwareAddr{0x2e, 0x60, byte(olt.ID), byte(p.ID), byte(o.ID), byte(k)}
193 service, err := NewService(s.Name, mac, o, nextCtag[s.Name], nextStag[s.Name],
194 s.NeedsEapol, s.NeedsDchp, s.NeedsIgmp, s.TechnologyProfileID, s.UniTagMatch,
195 s.ConfigureMacAddress, s.UsPonCTagPriority, s.UsPonSTagPriority, s.DsPonCTagPriority, s.DsPonSTagPriority)
196
197 if err != nil {
198 oltLogger.WithFields(log.Fields{
199 "Err": err.Error(),
200 }).Fatal("Can't create Service")
201 }
202
203 o.Services = append(o.Services, service)
Matteo Scandolof65e6872020-04-15 15:18:43 -0700204 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700205 p.Onus = append(p.Onus, o)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700206 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700207 olt.Pons = append(olt.Pons, p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700208 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100209
Shrey Baid688b4242020-07-10 20:40:10 +0530210 if !isMock {
Matteo Scandolod32c3822019-11-26 15:57:46 -0700211 if err := olt.InternalState.Event("initialize"); err != nil {
212 log.Errorf("Error initializing OLT: %v", err)
213 return nil
214 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100215 }
216
Pragya Arya324337e2020-02-20 14:35:08 +0530217 if olt.PublishEvents {
218 log.Debugf("BBSim event publishing is enabled")
219 // Create a channel to write event messages
220 olt.EventChannel = make(chan common.Event, 100)
221 }
222
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700223 return &olt
224}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700225
Shrey Baid688b4242020-07-10 20:40:10 +0530226func (o *OltDevice) InitOlt() {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100227
228 if oltServer == nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800229 oltServer, _ = o.newOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100230 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800231 // FIXME there should never be a server running if we are initializing the OLT
232 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100233 }
234
235 // create new channel for processOltMessages Go routine
236 o.channel = make(chan Message)
237
238 o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
239 // FIXME we are assuming we have only one NNI
240 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800241 // NOTE we want to make sure the state is down when we initialize the OLT,
242 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
243 // in-band management
244 o.Nnis[0].OperState.SetState("down")
245 ch, handle, err := o.Nnis[0].NewVethChan()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100246 if err == nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800247 oltLogger.WithFields(log.Fields{
248 "Type": o.Nnis[0].Type,
249 "IntfId": o.Nnis[0].ID,
250 "OperState": o.Nnis[0].OperState.Current(),
251 }).Info("NNI Channel created")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100252 o.nniPktInChannel = ch
Matteo Scandolo401503a2019-12-11 14:48:14 -0800253 o.nniHandle = handle
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100254 } else {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800255 oltLogger.Errorf("Error getting NNI channel: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100256 }
257 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700258}
259
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800260func (o *OltDevice) RestartOLT() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100261
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700262 softReboot := false
Matteo Scandolo4a036262020-08-17 15:56:13 -0700263 rebootDelay := common.Config.Olt.OltRebootDelay
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800264
265 oltLogger.WithFields(log.Fields{
266 "oltId": o.ID,
267 }).Infof("Simulating OLT restart... (%ds)", rebootDelay)
268
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700269 if o.InternalState.Is("enabled") {
270 oltLogger.WithFields(log.Fields{
271 "oltId": o.ID,
272 }).Info("This is an OLT soft reboot")
273 softReboot = true
274 }
275
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800276 // transition internal state to deleted
277 if err := o.InternalState.Event("delete"); err != nil {
278 oltLogger.WithFields(log.Fields{
279 "oltId": o.ID,
280 }).Errorf("Error deleting OLT: %v", err)
281 return err
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100282 }
283
284 // TODO handle hard poweroff (i.e. no indications sent to Voltha) vs soft poweroff
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800285 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
286 if err := o.StopOltServer(); err != nil {
Pragya Arya2225f202020-01-29 18:05:01 +0530287 oltLogger.Errorf("Error in stopping OLT server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100288 return err
289 }
290
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700291 if softReboot {
292 for _, pon := range o.Pons {
293 if pon.InternalState.Current() == "enabled" {
294 // disable PONs
295 msg := Message{
296 Type: PonIndication,
297 Data: PonIndicationMessage{
298 OperState: DOWN,
299 PonPortID: pon.ID,
300 },
301 }
302 o.channel <- msg
303 }
304
305 for _, onu := range pon.Onus {
306 _ = onu.InternalState.Event("disable")
307 }
308 }
309 } else {
310 // PONs are already handled in the Disable call
311 for _, pon := range olt.Pons {
312 // ONUs are not automatically disabled when a PON goes down
313 // as it's possible that it's an admin down and in that case the ONUs need to keep their state
314 for _, onu := range pon.Onus {
315 _ = onu.InternalState.Event("disable")
316 }
Pragya Arya2225f202020-01-29 18:05:01 +0530317 }
318 }
319
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100320 // terminate the OLT's processOltMessages go routine
321 close(o.channel)
322 // terminate the OLT's processNniPacketIns go routine
Andy Bavier421f4d52020-01-21 15:39:22 -0700323 go o.nniHandle.Close()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100324 close(o.nniPktInChannel)
Matteo Scandoloe9f5a6b2020-09-16 15:54:38 -0700325 o.enableContextCancel()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100326
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100327 time.Sleep(time.Duration(rebootDelay) * time.Second)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100328
329 if err := o.InternalState.Event("initialize"); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800330 oltLogger.WithFields(log.Fields{
331 "oltId": o.ID,
332 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100333 return err
334 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800335 oltLogger.WithFields(log.Fields{
336 "oltId": o.ID,
337 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100338 return nil
339}
340
341// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800342func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700343 address := common.Config.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700344 lis, err := net.Listen("tcp", address)
345 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700346 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700347 }
348 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100349
Matteo Scandolo4747d292019-08-05 11:50:18 -0700350 openolt.RegisterOpenoltServer(grpcServer, o)
351
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100352 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700353
Shrey Baid688b4242020-07-10 20:40:10 +0530354 go func() { _ = grpcServer.Serve(lis) }()
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100355 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700356
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100357 return grpcServer, nil
358}
359
360// StopOltServer stops the OpenOLT grpc server
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800361func (o *OltDevice) StopOltServer() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100362 // TODO handle poweroff vs graceful shutdown
363 if oltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800364 oltLogger.WithFields(log.Fields{
365 "oltId": o.SerialNumber,
366 }).Warnf("Stopping OLT gRPC server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100367 oltServer.Stop()
368 oltServer = nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700369 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800370
Matteo Scandolo4747d292019-08-05 11:50:18 -0700371 return nil
372}
373
374// Device Methods
375
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100376// Enable implements the OpenOLT EnableIndicationServer functionality
Shrey Baid688b4242020-07-10 20:40:10 +0530377func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700378 oltLogger.Debug("Enable OLT called")
Pragya Arya2225f202020-01-29 18:05:01 +0530379 rebootFlag := false
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700380
David Bainbridge103cf022019-12-16 20:11:35 +0000381 // If enabled has already been called then an enabled context has
382 // been created. If this is the case then we want to cancel all the
383 // proessing loops associated with that enable before we recreate
384 // new ones
385 o.Lock()
386 if o.enableContext != nil && o.enableContextCancel != nil {
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700387 oltLogger.Info("This is an OLT reboot")
David Bainbridge103cf022019-12-16 20:11:35 +0000388 o.enableContextCancel()
Pragya Arya2225f202020-01-29 18:05:01 +0530389 rebootFlag = true
David Bainbridge103cf022019-12-16 20:11:35 +0000390 }
391 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
392 o.Unlock()
393
Matteo Scandolo4747d292019-08-05 11:50:18 -0700394 wg := sync.WaitGroup{}
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800395 wg.Add(3)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700396
Matteo Scandolo4a036262020-08-17 15:56:13 -0700397 o.OpenoltStream = stream
Pragya Arya1cbefa42020-01-13 12:15:29 +0530398
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100399 // create Go routine to process all OLT events
David Bainbridge103cf022019-12-16 20:11:35 +0000400 go o.processOltMessages(o.enableContext, stream, &wg)
401 go o.processNniPacketIns(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700402
403 // enable the OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100404 oltMsg := Message{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700405 Type: OltIndication,
406 Data: OltIndicationMessage{
407 OperState: UP,
408 },
409 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100410 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700411
412 // send NNI Port Indications
413 for _, nni := range o.Nnis {
414 msg := Message{
415 Type: NniIndication,
416 Data: NniIndicationMessage{
417 OperState: UP,
418 NniPortID: nni.ID,
419 },
420 }
421 o.channel <- msg
422 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100423
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800424 go o.processOmciMessages(o.enableContext, stream, &wg)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100425
Shrey Baid688b4242020-07-10 20:40:10 +0530426 if rebootFlag {
Pragya Arya2225f202020-01-29 18:05:01 +0530427 for _, pon := range o.Pons {
428 if pon.InternalState.Current() == "disabled" {
429 msg := Message{
430 Type: PonIndication,
431 Data: PonIndicationMessage{
432 OperState: UP,
433 PonPortID: pon.ID,
434 },
435 }
436 o.channel <- msg
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000437 }
Pragya Arya2225f202020-01-29 18:05:01 +0530438 }
439 } else {
440
441 // 1. controlledActivation == Default: Send both PON and ONUs indications
442 // 2. controlledActivation == only-onu: that means only ONUs will be controlled activated, so auto send PON indications
443
444 if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
445 // send PON Port indications
446 for _, pon := range o.Pons {
447 msg := Message{
448 Type: PonIndication,
449 Data: PonIndicationMessage{
450 OperState: UP,
451 PonPortID: pon.ID,
452 },
453 }
454 o.channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700455 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700456 }
457 }
458
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800459 oltLogger.Debug("Enable OLT Done")
Pragya Arya996a0892020-03-09 21:47:52 +0530460
461 if !o.enablePerf {
462 // Start a go routine to send periodic port stats to openolt adapter
463 go o.periodicPortStats(o.enableContext)
464 }
465
Matteo Scandolo4747d292019-08-05 11:50:18 -0700466 wg.Wait()
Matteo Scandolo4747d292019-08-05 11:50:18 -0700467}
468
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800469func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400470 ch := omcisim.GetChannel()
471
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100472 oltLogger.Debug("Starting OMCI Indication Channel")
William Kurkian9dadc5b2019-10-22 13:51:57 -0400473
David Bainbridge103cf022019-12-16 20:11:35 +0000474loop:
475 for {
476 select {
477 case <-ctx.Done():
478 oltLogger.Debug("OMCI processing canceled via context")
479 break loop
480 case message, ok := <-ch:
481 if !ok || ctx.Err() != nil {
482 oltLogger.Debug("OMCI processing canceled via channel close")
483 break loop
484 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800485
486 oltLogger.WithFields(log.Fields{
487 "messageType": message.Type,
488 "OnuId": message.Data.OnuId,
489 "IntfId": message.Data.IntfId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700490 }).Debug("Received message on OMCI Sim channel")
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800491
David Bainbridge103cf022019-12-16 20:11:35 +0000492 onuId := message.Data.OnuId
493 intfId := message.Data.IntfId
494 onu, err := o.FindOnuById(intfId, onuId)
495 if err != nil {
496 oltLogger.Errorf("Failed to find onu: %v", err)
497 continue
498 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800499 go onu.processOmciMessage(message, stream)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400500 }
William Kurkian9dadc5b2019-10-22 13:51:57 -0400501 }
David Bainbridge103cf022019-12-16 20:11:35 +0000502
503 wg.Done()
William Kurkian9dadc5b2019-10-22 13:51:57 -0400504}
505
Pragya Arya996a0892020-03-09 21:47:52 +0530506func (o *OltDevice) periodicPortStats(ctx context.Context) {
507 var portStats *openolt.PortStatistics
508 for {
509 select {
510 case <-time.After(time.Duration(o.PortStatsInterval) * time.Second):
511 // send NNI port stats
512 for _, port := range o.Nnis {
513 incrementStat := true
514 if port.OperState.Current() == "down" {
515 incrementStat = false
516 }
517 portStats, port.PacketCount = getPortStats(port.PacketCount, incrementStat)
518 o.sendPortStatsIndication(portStats, port.ID, port.Type)
519 }
520
521 // send PON port stats
522 for _, port := range o.Pons {
523 incrementStat := true
524 // do not increment port stats if PON port is down or no ONU is activated on PON port
525 if port.OperState.Current() == "down" || port.GetNumOfActiveOnus() < 1 {
526 incrementStat = false
527 }
528 portStats, port.PacketCount = getPortStats(port.PacketCount, incrementStat)
529 o.sendPortStatsIndication(portStats, port.ID, port.Type)
530 }
531 case <-ctx.Done():
532 log.Debug("Stop sending port stats")
533 return
534 }
535
536 }
537}
538
Matteo Scandolo4747d292019-08-05 11:50:18 -0700539// Helpers method
540
Shrey Baid688b4242020-07-10 20:40:10 +0530541func (o *OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700542 for _, pon := range o.Pons {
543 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700544 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700545 }
546 }
Shrey Baid688b4242020-07-10 20:40:10 +0530547 return nil, fmt.Errorf("Cannot find PonPort with id %d in OLT %d", id, o.ID)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700548}
549
Shrey Baid688b4242020-07-10 20:40:10 +0530550func (o *OltDevice) getNniById(id uint32) (*NniPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700551 for _, nni := range o.Nnis {
552 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700553 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700554 }
555 }
Shrey Baid688b4242020-07-10 20:40:10 +0530556 return nil, fmt.Errorf("Cannot find NniPort with id %d in OLT %d", id, o.ID)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700557}
558
Scott Baker41724b82020-01-21 19:54:53 -0800559func (o *OltDevice) sendAlarmIndication(alarmInd *openolt.AlarmIndication, stream openolt.Openolt_EnableIndicationServer) {
560 data := &openolt.Indication_AlarmInd{AlarmInd: alarmInd}
561 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
562 oltLogger.Errorf("Failed to send Alarm Indication: %v", err)
563 return
564 }
565
566 oltLogger.WithFields(log.Fields{
567 "AlarmIndication": alarmInd,
568 }).Debug("Sent Indication_AlarmInd")
569}
570
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100571func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700572 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
573 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700574 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800575 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700576 }
577
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700578 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700579 "OperState": msg.OperState,
580 }).Debug("Sent Indication_OltInd")
581}
582
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100583func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700584 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800585 if msg.OperState == UP {
586 if err := nni.OperState.Event("enable"); err != nil {
587 log.WithFields(log.Fields{
588 "Type": nni.Type,
589 "IntfId": nni.ID,
590 "OperState": nni.OperState.Current(),
591 }).Errorf("Can't move NNI Port to enabled state: %v", err)
592 }
593 } else if msg.OperState == DOWN {
594 if err := nni.OperState.Event("disable"); err != nil {
595 log.WithFields(log.Fields{
596 "Type": nni.Type,
597 "IntfId": nni.ID,
598 "OperState": nni.OperState.Current(),
599 }).Errorf("Can't move NNI Port to disable state: %v", err)
600 }
601 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700602 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700603 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700604 Type: nni.Type,
605 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700606 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700607 }}
608
609 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700610 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800611 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700612 }
613
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700614 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700615 "Type": nni.Type,
616 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700617 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700618 }).Debug("Sent Indication_IntfOperInd for NNI")
619}
620
Pragya Arya2225f202020-01-29 18:05:01 +0530621func (o *OltDevice) sendPonIndication(ponPortID uint32) {
622
Matteo Scandolo4a036262020-08-17 15:56:13 -0700623 stream := o.OpenoltStream
Pragya Arya2225f202020-01-29 18:05:01 +0530624 pon, _ := o.GetPonById(ponPortID)
625 // Send IntfIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700626 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700627 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700628 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700629 }}
630
631 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700632 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800633 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700634 }
635
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700636 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700637 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700638 "OperState": pon.OperState.Current(),
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700639 }).Debug("Sent Indication_IntfInd for PON")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700640
Pragya Arya2225f202020-01-29 18:05:01 +0530641 // Send IntfOperIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700642 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700643 Type: pon.Type,
644 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700645 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700646 }}
647
648 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700649 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800650 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700651 }
652
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700653 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700654 "Type": pon.Type,
655 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700656 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700657 }).Debug("Sent Indication_IntfOperInd for PON")
658}
659
Pragya Arya996a0892020-03-09 21:47:52 +0530660func (o *OltDevice) sendPortStatsIndication(stats *openolt.PortStatistics, portID uint32, portType string) {
Shrey Baid55f328c2020-07-07 19:20:42 +0530661 if o.InternalState.Current() == "enabled" {
662 oltLogger.WithFields(log.Fields{
663 "Type": portType,
664 "IntfId": portID,
665 }).Trace("Sending port stats")
666 stats.IntfId = InterfaceIDToPortNo(portID, portType)
667 data := &openolt.Indication_PortStats{
668 PortStats: stats,
669 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700670 stream := o.OpenoltStream
Shrey Baid55f328c2020-07-07 19:20:42 +0530671 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
672 oltLogger.Errorf("Failed to send PortStats: %v", err)
673 return
674 }
Pragya Arya996a0892020-03-09 21:47:52 +0530675 }
676}
677
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100678// processOltMessages handles messages received over the OpenOLT interface
David Bainbridge103cf022019-12-16 20:11:35 +0000679func (o *OltDevice) processOltMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100680 oltLogger.Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000681 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700682
David Bainbridge103cf022019-12-16 20:11:35 +0000683loop:
684 for {
685 select {
686 case <-ctx.Done():
687 oltLogger.Debug("OLT Indication processing canceled via context")
688 break loop
689 case message, ok := <-ch:
690 if !ok || ctx.Err() != nil {
691 oltLogger.Debug("OLT Indication processing canceled via closed channel")
692 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700693 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700694
David Bainbridge103cf022019-12-16 20:11:35 +0000695 oltLogger.WithFields(log.Fields{
696 "oltId": o.ID,
697 "messageType": message.Type,
698 }).Trace("Received message")
699
700 switch message.Type {
701 case OltIndication:
702 msg, _ := message.Data.(OltIndicationMessage)
703 if msg.OperState == UP {
Shrey Baid688b4242020-07-10 20:40:10 +0530704 _ = o.InternalState.Event("enable")
705 _ = o.OperState.Event("enable")
David Bainbridge103cf022019-12-16 20:11:35 +0000706 } else if msg.OperState == DOWN {
Shrey Baid688b4242020-07-10 20:40:10 +0530707 _ = o.InternalState.Event("disable")
708 _ = o.OperState.Event("disable")
David Bainbridge103cf022019-12-16 20:11:35 +0000709 }
710 o.sendOltIndication(msg, stream)
Scott Baker41724b82020-01-21 19:54:53 -0800711 case AlarmIndication:
712 alarmInd, _ := message.Data.(*openolt.AlarmIndication)
713 o.sendAlarmIndication(alarmInd, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000714 case NniIndication:
715 msg, _ := message.Data.(NniIndicationMessage)
716 o.sendNniIndication(msg, stream)
717 case PonIndication:
718 msg, _ := message.Data.(PonIndicationMessage)
Pragya Arya2225f202020-01-29 18:05:01 +0530719 pon, _ := o.GetPonById(msg.PonPortID)
720 if msg.OperState == UP {
Hardik Windlassad790cb2020-06-17 21:26:22 +0530721 if err := pon.OperState.Event("enable"); err != nil {
722 oltLogger.WithFields(log.Fields{
723 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800724 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530725 }).Error("Can't Enable Oper state for PON Port")
726 }
727 if err := pon.InternalState.Event("enable"); err != nil {
728 oltLogger.WithFields(log.Fields{
729 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800730 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530731 }).Error("Can't Enable Internal state for PON Port")
732 }
Pragya Arya2225f202020-01-29 18:05:01 +0530733 } else if msg.OperState == DOWN {
Hardik Windlassad790cb2020-06-17 21:26:22 +0530734 if err := pon.OperState.Event("disable"); err != nil {
735 oltLogger.WithFields(log.Fields{
736 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800737 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530738 }).Error("Can't Disable Oper state for PON Port")
739 }
740 if err := pon.InternalState.Event("disable"); err != nil {
741 oltLogger.WithFields(log.Fields{
742 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800743 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530744 }).Error("Can't Disable Internal state for PON Port")
745 }
Pragya Arya2225f202020-01-29 18:05:01 +0530746 }
David Bainbridge103cf022019-12-16 20:11:35 +0000747 default:
748 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
749 }
750 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700751 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100752 wg.Done()
753 oltLogger.Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700754}
755
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100756// processNniPacketIns handles messages received over the NNI interface
David Bainbridge103cf022019-12-16 20:11:35 +0000757func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700758 oltLogger.WithFields(log.Fields{
759 "nniChannel": o.nniPktInChannel,
Matteo Scandolo401503a2019-12-11 14:48:14 -0800760 }).Debug("Started Processing Packets arriving from the NNI")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700761 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700762
David Bainbridge103cf022019-12-16 20:11:35 +0000763 ch := o.nniPktInChannel
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700764
David Bainbridge103cf022019-12-16 20:11:35 +0000765loop:
766 for {
767 select {
768 case <-ctx.Done():
769 oltLogger.Debug("NNI Indication processing canceled via context")
770 break loop
771 case message, ok := <-ch:
772 if !ok || ctx.Err() != nil {
773 oltLogger.Debug("NNI Indication processing canceled via channel closed")
774 break loop
775 }
776 oltLogger.Tracef("Received packets on NNI Channel")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700777
David Bainbridge103cf022019-12-16 20:11:35 +0000778 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700779
David Bainbridge103cf022019-12-16 20:11:35 +0000780 if err != nil {
781 log.WithFields(log.Fields{
782 "IntfType": "nni",
783 "IntfId": nniId,
784 "Pkt": message.Pkt.Data(),
785 }).Error("Can't find Dst MacAddress in packet")
786 return
787 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700788
Matteo Scandolo4a036262020-08-17 15:56:13 -0700789 s, err := o.FindServiceByMacAddress(onuMac)
David Bainbridge103cf022019-12-16 20:11:35 +0000790 if err != nil {
791 log.WithFields(log.Fields{
792 "IntfType": "nni",
793 "IntfId": nniId,
794 "Pkt": message.Pkt.Data(),
795 "MacAddress": onuMac.String(),
796 }).Error("Can't find ONU with MacAddress")
797 return
798 }
799
Matteo Scandolo4a036262020-08-17 15:56:13 -0700800 service := s.(*Service)
801
Matteo Scandolo8d281372020-09-03 16:23:37 -0700802 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(service.STag, service.CTag, message.Pkt, service.UsPonCTagPriority)
David Bainbridge103cf022019-12-16 20:11:35 +0000803 if err != nil {
804 log.Error("Fail to add double tag to packet")
805 }
806
807 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
808 IntfType: "nni",
809 IntfId: nniId,
810 Pkt: doubleTaggedPkt.Data()}}
811 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
812 oltLogger.WithFields(log.Fields{
813 "IntfType": data.PktInd.IntfType,
814 "IntfId": nniId,
815 "Pkt": doubleTaggedPkt.Data(),
816 }).Errorf("Fail to send PktInd indication: %v", err)
817 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700818 oltLogger.WithFields(log.Fields{
819 "IntfType": data.PktInd.IntfType,
820 "IntfId": nniId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700821 "Pkt": hex.EncodeToString(doubleTaggedPkt.Data()),
822 "OnuSn": service.Onu.Sn(),
823 }).Trace("Sent PktInd indication (from NNI to VOLTHA)")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700824 }
825 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100826 wg.Done()
827 oltLogger.WithFields(log.Fields{
828 "nniChannel": o.nniPktInChannel,
829 }).Warn("Stopped handling NNI Channel")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700830}
831
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700832// returns an ONU with a given Serial Number
Shrey Baid688b4242020-07-10 20:40:10 +0530833func (o *OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200834 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700835 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700836 for _, pon := range o.Pons {
837 for _, onu := range pon.Onus {
838 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700839 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700840 }
841 }
842 }
843
Shrey Baid688b4242020-07-10 20:40:10 +0530844 return &Onu{}, fmt.Errorf("cannot-find-onu-by-serial-number-%s", serialNumber)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700845}
846
William Kurkian9dadc5b2019-10-22 13:51:57 -0400847// returns an ONU with a given interface/Onu Id
Shrey Baid688b4242020-07-10 20:40:10 +0530848func (o *OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200849 // TODO this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400850 // memoizing it will remove the bottleneck
851 for _, pon := range o.Pons {
852 if pon.ID == intfId {
853 for _, onu := range pon.Onus {
854 if onu.ID == onuId {
855 return onu, nil
856 }
857 }
858 }
859 }
Shrey Baid688b4242020-07-10 20:40:10 +0530860 return &Onu{}, fmt.Errorf("cannot-find-onu-by-id-%v-%v", intfId, onuId)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400861}
862
Matteo Scandolo4a036262020-08-17 15:56:13 -0700863// returns a Service with a given Mac Address
864func (o *OltDevice) FindServiceByMacAddress(mac net.HardwareAddr) (ServiceIf, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200865 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700866 // memoizing it will remove the bottleneck
867 for _, pon := range o.Pons {
868 for _, onu := range pon.Onus {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700869 s, err := onu.findServiceByMacAddress(mac)
870 if err == nil {
871 return s, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700872 }
873 }
874 }
875
Matteo Scandolo4a036262020-08-17 15:56:13 -0700876 return nil, fmt.Errorf("cannot-find-service-by-mac-address-%s", mac)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700877}
878
Matteo Scandolo4747d292019-08-05 11:50:18 -0700879// GRPC Endpoints
880
Shrey Baid688b4242020-07-10 20:40:10 +0530881func (o *OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700882 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700883 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700884 }).Info("Received ActivateOnu call from VOLTHA")
Pragya Arya324337e2020-02-20 14:35:08 +0530885 publishEvent("ONU-activate-indication-received", int32(onu.IntfId), int32(onu.OnuId), onuSnToString(onu.SerialNumber))
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700886
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700887 pon, _ := o.GetPonById(onu.IntfId)
888 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
William Kurkian0418bc82019-11-06 12:16:24 -0500889 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700890
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700891 if err := _onu.OperState.Event("enable"); err != nil {
892 oltLogger.WithFields(log.Fields{
893 "IntfId": _onu.PonPortID,
894 "OnuSn": _onu.Sn(),
895 "OnuId": _onu.ID,
896 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700897 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700898 if err := _onu.InternalState.Event("enable"); err != nil {
899 oltLogger.WithFields(log.Fields{
900 "IntfId": _onu.PonPortID,
901 "OnuSn": _onu.Sn(),
902 "OnuId": _onu.ID,
903 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
904 }
905
906 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
907
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700908 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700909}
910
Shrey Baid688b4242020-07-10 20:40:10 +0530911func (o *OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700912 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700913 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700914}
915
Shrey Baid688b4242020-07-10 20:40:10 +0530916func (o *OltDevice) DeleteOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Pragya Arya1cbefa42020-01-13 12:15:29 +0530917 oltLogger.WithFields(log.Fields{
918 "IntfId": onu.IntfId,
919 "OnuId": onu.OnuId,
920 }).Info("Received DeleteOnu call from VOLTHA")
921
922 pon, err := o.GetPonById(onu.IntfId)
923 if err != nil {
924 oltLogger.WithFields(log.Fields{
925 "OnuId": onu.OnuId,
926 "IntfId": onu.IntfId,
927 "err": err,
928 }).Error("Can't find PonPort")
929 }
930 _onu, err := pon.GetOnuById(onu.OnuId)
931 if err != nil {
932 oltLogger.WithFields(log.Fields{
933 "OnuId": onu.OnuId,
934 "IntfId": onu.IntfId,
935 "err": err,
936 }).Error("Can't find Onu")
937 }
938
Hardik Windlassad790cb2020-06-17 21:26:22 +0530939 if err := _onu.InternalState.Event("disable"); err != nil {
Pragya Arya1cbefa42020-01-13 12:15:29 +0530940 oltLogger.WithFields(log.Fields{
941 "IntfId": _onu.PonPortID,
942 "OnuSn": _onu.Sn(),
943 "OnuId": _onu.ID,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530944 }).Infof("Failed to transition ONU to disabled state: %s", err.Error())
945 }
946
Hardik Windlassad790cb2020-06-17 21:26:22 +0530947 // ONU Re-Discovery
948 if o.InternalState.Current() == "enabled" && pon.InternalState.Current() == "enabled" {
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530949 go _onu.ReDiscoverOnu()
Pragya Arya1cbefa42020-01-13 12:15:29 +0530950 }
951
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700952 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700953}
954
Shrey Baid688b4242020-07-10 20:40:10 +0530955func (o *OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700956 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800957 oltLogger.WithFields(log.Fields{
958 "oltId": o.ID,
959 }).Info("Disabling OLT")
Pragya Arya324337e2020-02-20 14:35:08 +0530960 publishEvent("OLT-disable-received", -1, -1, "")
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800961
Matteo Scandolo401503a2019-12-11 14:48:14 -0800962 for _, pon := range o.Pons {
Pragya Arya2225f202020-01-29 18:05:01 +0530963 if pon.InternalState.Current() == "enabled" {
964 // disable PONs
965 msg := Message{
966 Type: PonIndication,
967 Data: PonIndicationMessage{
968 OperState: DOWN,
969 PonPortID: pon.ID,
970 },
971 }
972 o.channel <- msg
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800973 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800974 }
975
Matteo Scandolo401503a2019-12-11 14:48:14 -0800976 // Note that we are not disabling the NNI as the real OLT does not.
977 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800978
979 // disable OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100980 oltMsg := Message{
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700981 Type: OltIndication,
982 Data: OltIndicationMessage{
983 OperState: DOWN,
984 },
985 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100986 o.channel <- oltMsg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700987 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700988}
989
Shrey Baid688b4242020-07-10 20:40:10 +0530990func (o *OltDevice) DisablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
Hardik Windlassad790cb2020-06-17 21:26:22 +0530991 oltLogger.Infof("DisablePonIf request received for PON %d", intf.IntfId)
Andrea Campanella340b9ea2020-04-28 18:34:01 +0200992 ponID := intf.GetIntfId()
993 pon, _ := o.GetPonById(intf.IntfId)
Andrea Campanella340b9ea2020-04-28 18:34:01 +0200994
995 msg := Message{
996 Type: PonIndication,
997 Data: PonIndicationMessage{
998 OperState: DOWN,
999 PonPortID: ponID,
1000 },
1001 }
1002 o.channel <- msg
1003
1004 for _, onu := range pon.Onus {
1005
1006 onuIndication := OnuIndicationMessage{
1007 OperState: DOWN,
1008 PonPortID: ponID,
1009 OnuID: onu.ID,
1010 OnuSN: onu.SerialNumber,
1011 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001012 onu.sendOnuIndication(onuIndication, o.OpenoltStream)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001013
1014 }
1015
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001016 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001017}
1018
Zdravko Bozakov681364d2019-11-10 14:28:46 +01001019func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001020 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Pragya Arya324337e2020-02-20 14:35:08 +05301021 publishEvent("OLT-enable-received", -1, -1, "")
Matteo Scandolo4747d292019-08-05 11:50:18 -07001022 o.Enable(stream)
1023 return nil
1024}
1025
Shrey Baid688b4242020-07-10 20:40:10 +05301026func (o *OltDevice) EnablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
Hardik Windlassad790cb2020-06-17 21:26:22 +05301027 oltLogger.Infof("EnablePonIf request received for PON %d", intf.IntfId)
Pragya Arya2225f202020-01-29 18:05:01 +05301028 ponID := intf.GetIntfId()
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001029 pon, _ := o.GetPonById(intf.IntfId)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001030
Pragya Arya2225f202020-01-29 18:05:01 +05301031 msg := Message{
1032 Type: PonIndication,
1033 Data: PonIndicationMessage{
1034 OperState: UP,
1035 PonPortID: ponID,
1036 },
1037 }
1038 o.channel <- msg
1039
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001040 for _, onu := range pon.Onus {
1041
1042 onuIndication := OnuIndicationMessage{
1043 OperState: UP,
1044 PonPortID: ponID,
1045 OnuID: onu.ID,
1046 OnuSN: onu.SerialNumber,
1047 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001048 onu.sendOnuIndication(onuIndication, o.OpenoltStream)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001049
1050 }
1051
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001052 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001053}
1054
Shrey Baid688b4242020-07-10 20:40:10 +05301055func (o *OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001056 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001057 "IntfId": flow.AccessIntfId,
1058 "OnuId": flow.OnuId,
1059 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001060 "InnerVlan": flow.Classifier.IVid,
1061 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001062 "FlowType": flow.FlowType,
1063 "FlowId": flow.FlowId,
1064 "UniID": flow.UniId,
1065 "PortNo": flow.PortNo,
Pragya Arya8bdb4532020-03-02 17:08:09 +05301066 }).Tracef("OLT receives FlowAdd")
1067
1068 flowKey := FlowKey{}
1069 if !o.enablePerf {
1070 flowKey = FlowKey{ID: flow.FlowId, Direction: flow.FlowType}
1071 olt.Flows[flowKey] = *flow
1072 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001073
1074 if flow.AccessIntfId == -1 {
1075 oltLogger.WithFields(log.Fields{
1076 "FlowId": flow.FlowId,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001077 }).Debug("Adding OLT flow")
Jonathan Hartb5fc46a2020-03-31 16:42:31 -07001078 } else if flow.FlowType == "multicast" {
1079 oltLogger.WithFields(log.Fields{
Matteo Scandolo618a6582020-09-09 12:21:29 -07001080 "Cookie": flow.Cookie,
1081 "DstPort": flow.Classifier.DstPort,
1082 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
1083 "FlowId": flow.FlowId,
1084 "FlowType": flow.FlowType,
1085 "GemportId": flow.GemportId,
1086 "InnerVlan": flow.Classifier.IVid,
1087 "IntfId": flow.AccessIntfId,
1088 "IpProto": flow.Classifier.IpProto,
1089 "OnuId": flow.OnuId,
1090 "OuterVlan": flow.Classifier.OVid,
1091 "PortNo": flow.PortNo,
1092 "SrcPort": flow.Classifier.SrcPort,
1093 "UniID": flow.UniId,
1094 "ClassifierOPbits": flow.Classifier.OPbits,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001095 }).Debug("Adding OLT multicast flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001096 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001097 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -07001098 if err != nil {
1099 oltLogger.WithFields(log.Fields{
1100 "OnuId": flow.OnuId,
1101 "IntfId": flow.AccessIntfId,
1102 "err": err,
1103 }).Error("Can't find PonPort")
1104 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001105 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -07001106 if err != nil {
1107 oltLogger.WithFields(log.Fields{
1108 "OnuId": flow.OnuId,
1109 "IntfId": flow.AccessIntfId,
1110 "err": err,
1111 }).Error("Can't find Onu")
Jonathan Hartb5fc46a2020-03-31 16:42:31 -07001112 return nil, err
Matteo Scandolo27428702019-10-11 16:21:16 -07001113 }
Pragya Arya8bdb4532020-03-02 17:08:09 +05301114 if !o.enablePerf {
1115 onu.Flows = append(onu.Flows, flowKey)
Pragya Arya1d5ffb82020-03-20 18:51:37 +05301116 // Generate event on first flow for ONU
1117 if len(onu.Flows) == 1 {
1118 publishEvent("Flow-add-received", int32(onu.PonPortID), int32(onu.ID), onuSnToString(onu.SerialNumber))
1119 }
Pragya Arya8bdb4532020-03-02 17:08:09 +05301120 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001121
1122 msg := Message{
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001123 Type: FlowAdd,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001124 Data: OnuFlowUpdateMessage{
1125 PonPortID: pon.ID,
1126 OnuID: onu.ID,
1127 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001128 },
1129 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001130 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001131 }
1132
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001133 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001134}
1135
Pragya Arya8bdb4532020-03-02 17:08:09 +05301136// FlowRemove request from VOLTHA
Shrey Baid688b4242020-07-10 20:40:10 +05301137func (o *OltDevice) FlowRemove(_ context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001138
Pragya Arya8bdb4532020-03-02 17:08:09 +05301139 oltLogger.WithFields(log.Fields{
Shrey Baid55f328c2020-07-07 19:20:42 +05301140 "FlowId": flow.FlowId,
1141 "FlowType": flow.FlowType,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001142 }).Debug("OLT receives FlowRemove")
Pragya Arya8bdb4532020-03-02 17:08:09 +05301143
1144 if !o.enablePerf { // remove only if flow were stored
1145 flowKey := FlowKey{
1146 ID: flow.FlowId,
1147 Direction: flow.FlowType,
1148 }
1149
1150 // Check if flow exists
1151 storedFlow, ok := o.Flows[flowKey]
1152 if !ok {
1153 oltLogger.Errorf("Flow %v not found", flow)
1154 return new(openolt.Empty), status.Errorf(codes.NotFound, "Flow not found")
1155 }
1156
1157 // if its ONU flow remove it from ONU also
1158 if storedFlow.AccessIntfId != -1 {
1159 pon := o.Pons[uint32(storedFlow.AccessIntfId)]
1160 onu, err := pon.GetOnuById(uint32(storedFlow.OnuId))
1161 if err != nil {
1162 oltLogger.WithFields(log.Fields{
1163 "OnuId": storedFlow.OnuId,
1164 "IntfId": storedFlow.AccessIntfId,
1165 "err": err,
1166 }).Error("ONU not found")
1167 return new(openolt.Empty), nil
1168 }
1169 onu.DeleteFlow(flowKey)
Pragya Arya1d5ffb82020-03-20 18:51:37 +05301170 publishEvent("Flow-remove-received", int32(onu.PonPortID), int32(onu.ID), onuSnToString(onu.SerialNumber))
Pragya Arya8bdb4532020-03-02 17:08:09 +05301171 }
1172
1173 // delete from olt flows
1174 delete(o.Flows, flowKey)
1175 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001176
1177 if flow.AccessIntfId == -1 {
1178 oltLogger.WithFields(log.Fields{
1179 "FlowId": flow.FlowId,
1180 }).Debug("Removing OLT flow")
1181 } else if flow.FlowType == "multicast" {
1182 oltLogger.WithFields(log.Fields{
1183 "FlowId": flow.FlowId,
1184 }).Debug("Removing OLT multicast flow")
1185 } else {
1186
1187 onu, err := o.GetOnuByFlowId(flow.FlowId)
1188 if err != nil {
1189 oltLogger.WithFields(log.Fields{
1190 "OnuId": flow.OnuId,
1191 "IntfId": flow.AccessIntfId,
1192 "err": err,
1193 }).Error("Can't find Onu")
1194 return nil, err
1195 }
1196
1197 msg := Message{
1198 Type: FlowRemoved,
1199 Data: OnuFlowUpdateMessage{
Shrey Baid55f328c2020-07-07 19:20:42 +05301200 Flow: flow,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001201 },
1202 }
1203 onu.Channel <- msg
1204 }
1205
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001206 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001207}
1208
Shrey Baid688b4242020-07-10 20:40:10 +05301209func (o *OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo18859852020-01-15 13:33:57 -08001210 res := openolt.Heartbeat{HeartbeatSignature: uint32(time.Now().Unix())}
1211 oltLogger.WithFields(log.Fields{
1212 "signature": res.HeartbeatSignature,
1213 }).Trace("HeartbeatCheck")
1214 return &res, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001215}
1216
Matteo Scandolo4f4ac792020-10-01 16:33:21 -07001217func (o *OltDevice) GetOnuByFlowId(flowId uint64) (*Onu, error) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001218 for _, pon := range o.Pons {
1219 for _, onu := range pon.Onus {
1220 for _, fId := range onu.FlowIds {
1221 if fId == flowId {
1222 return onu, nil
1223 }
1224 }
1225 }
1226 }
Shrey Baid688b4242020-07-10 20:40:10 +05301227 return nil, fmt.Errorf("Cannot find Onu by flowId %d", flowId)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001228}
1229
Shrey Baid688b4242020-07-10 20:40:10 +05301230func (o *OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -07001231
Matteo Scandoloda9cbe22019-08-19 16:05:10 -07001232 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001233 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -07001234 "PonPorts": o.NumPon,
1235 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -07001236 devinfo := new(openolt.DeviceInfo)
Matteo Scandolo4a036262020-08-17 15:56:13 -07001237 devinfo.Vendor = common.Config.Olt.Vendor
1238 devinfo.Model = common.Config.Olt.Model
1239 devinfo.HardwareVersion = common.Config.Olt.HardwareVersion
1240 devinfo.FirmwareVersion = common.Config.Olt.FirmwareVersion
1241 devinfo.Technology = common.Config.Olt.Technology
Matteo Scandoloda9cbe22019-08-19 16:05:10 -07001242 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -07001243 devinfo.OnuIdStart = 1
1244 devinfo.OnuIdEnd = 255
1245 devinfo.AllocIdStart = 1024
1246 devinfo.AllocIdEnd = 16383
1247 devinfo.GemportIdStart = 1024
1248 devinfo.GemportIdEnd = 65535
1249 devinfo.FlowIdStart = 1
1250 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -07001251 devinfo.DeviceSerialNumber = o.SerialNumber
Matteo Scandolo4a036262020-08-17 15:56:13 -07001252 devinfo.DeviceId = common.Config.Olt.DeviceId
Matteo Scandolo4747d292019-08-05 11:50:18 -07001253
1254 return devinfo, nil
1255}
1256
Shrey Baid688b4242020-07-10 20:40:10 +05301257func (o *OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Jonathan Hartacfa20e2020-03-31 15:20:14 -07001258 pon, err := o.GetPonById(omci_msg.IntfId)
1259 if err != nil {
1260 oltLogger.WithFields(log.Fields{
Matteo Scandolof65e6872020-04-15 15:18:43 -07001261 "error": err,
Jonathan Hartacfa20e2020-03-31 15:20:14 -07001262 "onu_id": omci_msg.OnuId,
1263 "pon_id": omci_msg.IntfId,
1264 }).Error("pon ID not found")
1265 return nil, err
1266 }
1267
1268 onu, err := pon.GetOnuById(omci_msg.OnuId)
1269 if err != nil {
1270 oltLogger.WithFields(log.Fields{
Matteo Scandolof65e6872020-04-15 15:18:43 -07001271 "error": err,
Jonathan Hartacfa20e2020-03-31 15:20:14 -07001272 "onu_id": omci_msg.OnuId,
1273 "pon_id": omci_msg.IntfId,
1274 }).Error("onu ID not found")
1275 return nil, err
1276 }
1277
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001278 oltLogger.WithFields(log.Fields{
1279 "IntfId": onu.PonPortID,
1280 "OnuId": onu.ID,
1281 "OnuSn": onu.Sn(),
1282 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001283 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001284 Type: OMCI,
1285 Data: OmciMessage{
1286 OnuSN: onu.SerialNumber,
1287 OnuID: onu.ID,
1288 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001289 },
1290 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001291 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001292 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001293}
1294
Shrey Baid688b4242020-07-10 20:40:10 +05301295func (o *OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001296 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -07001297 if err != nil {
1298 oltLogger.WithFields(log.Fields{
1299 "OnuId": onuPkt.OnuId,
1300 "IntfId": onuPkt.IntfId,
1301 "err": err,
1302 }).Error("Can't find PonPort")
1303 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001304 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -07001305 if err != nil {
1306 oltLogger.WithFields(log.Fields{
1307 "OnuId": onuPkt.OnuId,
1308 "IntfId": onuPkt.IntfId,
1309 "err": err,
1310 }).Error("Can't find Onu")
1311 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001312
Matteo Scandolo075b1892019-10-07 12:11:07 -07001313 oltLogger.WithFields(log.Fields{
1314 "IntfId": onu.PonPortID,
1315 "OnuId": onu.ID,
1316 "OnuSn": onu.Sn(),
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001317 "Packet": hex.EncodeToString(onuPkt.Pkt),
Matteo Scandolo75ed5b92020-09-03 09:03:16 -07001318 }).Trace("Received OnuPacketOut")
Matteo Scandolo075b1892019-10-07 12:11:07 -07001319
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001320 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo618a6582020-09-09 12:21:29 -07001321
1322 pktType, err := packetHandlers.GetPktType(rawpkt)
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001323 if err != nil {
1324 onuLogger.WithFields(log.Fields{
1325 "IntfId": onu.PonPortID,
1326 "OnuId": onu.ID,
1327 "OnuSn": onu.Sn(),
Matteo Scandolo618a6582020-09-09 12:21:29 -07001328 "Pkt": hex.EncodeToString(rawpkt.Data()),
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001329 }).Error("Can't find pktType in packet, droppint it")
1330 return new(openolt.Empty), nil
1331 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001332
Matteo Scandolo4a036262020-08-17 15:56:13 -07001333 pktMac, err := packetHandlers.GetDstMacAddressFromPacket(rawpkt)
Matteo Scandolo4a036262020-08-17 15:56:13 -07001334 if err != nil {
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001335 onuLogger.WithFields(log.Fields{
Matteo Scandolo4a036262020-08-17 15:56:13 -07001336 "IntfId": onu.PonPortID,
1337 "OnuId": onu.ID,
1338 "OnuSn": onu.Sn(),
1339 "Pkt": rawpkt.Data(),
1340 }).Error("Can't find Dst MacAddress in packet, droppint it")
1341 return new(openolt.Empty), nil
1342 }
1343
Matteo Scandolo075b1892019-10-07 12:11:07 -07001344 msg := Message{
1345 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001346 Data: OnuPacketMessage{
Matteo Scandolo4a036262020-08-17 15:56:13 -07001347 IntfId: onuPkt.IntfId,
1348 OnuId: onuPkt.OnuId,
1349 Packet: rawpkt,
1350 Type: pktType,
1351 MacAddress: pktMac,
Matteo Scandolo075b1892019-10-07 12:11:07 -07001352 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001353 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001354
Matteo Scandolo075b1892019-10-07 12:11:07 -07001355 onu.Channel <- msg
1356
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001357 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001358}
1359
Shrey Baid688b4242020-07-10 20:40:10 +05301360func (o *OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo635b2bf2020-09-04 10:23:40 -07001361
1362 // OLT Reboot is called in two cases:
1363 // - 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)
1364 // - when an OLT needs to be rebooted (voltcl device reboot)
1365
Matteo Scandolod02b79b2019-12-05 16:42:13 -08001366 oltLogger.WithFields(log.Fields{
1367 "oltId": o.ID,
1368 }).Info("Shutting down")
Pragya Arya324337e2020-02-20 14:35:08 +05301369 publishEvent("OLT-reboot-received", -1, -1, "")
Shrey Baid688b4242020-07-10 20:40:10 +05301370 go func() { _ = o.RestartOLT() }()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001371 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001372}
1373
Shrey Baid688b4242020-07-10 20:40:10 +05301374func (o *OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Pragya Arya6a708d62020-01-01 17:17:20 +05301375 oltLogger.WithFields(log.Fields{
1376 "oltId": o.ID,
1377 }).Info("Received ReenableOlt request from VOLTHA")
Pragya Arya324337e2020-02-20 14:35:08 +05301378 publishEvent("OLT-reenable-received", -1, -1, "")
Pragya Arya6a708d62020-01-01 17:17:20 +05301379
Pragya Arya2225f202020-01-29 18:05:01 +05301380 // enable OLT
1381 oltMsg := Message{
1382 Type: OltIndication,
1383 Data: OltIndicationMessage{
1384 OperState: UP,
1385 },
Pragya Arya1881df02020-01-29 18:05:01 +05301386 }
Pragya Arya2225f202020-01-29 18:05:01 +05301387 o.channel <- oltMsg
Pragya Arya6a708d62020-01-01 17:17:20 +05301388
Pragya Arya2225f202020-01-29 18:05:01 +05301389 for _, pon := range o.Pons {
1390 if pon.InternalState.Current() == "disabled" {
1391 msg := Message{
1392 Type: PonIndication,
1393 Data: PonIndicationMessage{
1394 OperState: UP,
1395 PonPortID: pon.ID,
1396 },
1397 }
1398 o.channel <- msg
1399 }
1400 }
Matteo Scandoloe60a5052020-02-07 00:31:14 +00001401
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001402 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001403}
1404
Shrey Baid688b4242020-07-10 20:40:10 +05301405func (o *OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001406 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
1407
Shrey Baid688b4242020-07-10 20:40:10 +05301408 _ = o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001409 // NOTE should we return an error if sendNniPakcet fails?
1410 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001411}
1412
Shrey Baid688b4242020-07-10 20:40:10 +05301413func (o *OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001414 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001415 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001416}
1417
Shrey Baid688b4242020-07-10 20:40:10 +05301418func (o *OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001419 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001420 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001421}
1422
Shrey Baid688b4242020-07-10 20:40:10 +05301423func (o *OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001424 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001425 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -07001426}
1427
Shrey Baid688b4242020-07-10 20:40:10 +05301428func (s *OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001429 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001430 return new(openolt.Empty), nil
1431}
1432
Shrey Baid688b4242020-07-10 20:40:10 +05301433func (s *OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001434 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001435 return new(openolt.Empty), nil
1436}
1437
Shrey Baid688b4242020-07-10 20:40:10 +05301438func (s *OltDevice) CreateTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Anand S Katti09541352020-01-29 15:54:01 +05301439 oltLogger.WithFields(log.Fields{
1440 "OnuId": trafficSchedulers.OnuId,
1441 "IntfId": trafficSchedulers.IntfId,
1442 "OnuPortNo": trafficSchedulers.PortNo,
1443 }).Info("received CreateTrafficSchedulers")
1444
1445 if !s.enablePerf {
1446 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1447 if err != nil {
1448 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1449 return new(openolt.Empty), err
1450 }
1451 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1452 if err != nil {
1453 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1454 return new(openolt.Empty), err
1455 }
1456 onu.TrafficSchedulers = trafficSchedulers
1457 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001458 return new(openolt.Empty), nil
1459}
1460
Shrey Baid688b4242020-07-10 20:40:10 +05301461func (s *OltDevice) RemoveTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Anand S Katti09541352020-01-29 15:54:01 +05301462 oltLogger.WithFields(log.Fields{
1463 "OnuId": trafficSchedulers.OnuId,
1464 "IntfId": trafficSchedulers.IntfId,
1465 "OnuPortNo": trafficSchedulers.PortNo,
1466 }).Info("received RemoveTrafficSchedulers")
1467 if !s.enablePerf {
1468 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1469 if err != nil {
1470 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1471 return new(openolt.Empty), err
1472 }
1473 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1474 if err != nil {
1475 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1476 return new(openolt.Empty), err
1477 }
1478
1479 onu.TrafficSchedulers = nil
1480 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001481 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001482}
Scott Baker41724b82020-01-21 19:54:53 -08001483
1484// assumes caller has properly formulated an openolt.AlarmIndication
Shrey Baid688b4242020-07-10 20:40:10 +05301485func (o *OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
Scott Baker41724b82020-01-21 19:54:53 -08001486 msg := Message{
1487 Type: AlarmIndication,
1488 Data: ind,
1489 }
1490
1491 o.channel <- msg
1492 return nil
1493}
Matteo Scandolo618a6582020-09-09 12:21:29 -07001494
1495func (o *OltDevice) PerformGroupOperation(ctx context.Context, group *openolt.Group) (*openolt.Empty, error) {
1496 oltLogger.WithFields(log.Fields{
1497 "GroupId": group.GroupId,
1498 "Command": group.Command,
1499 "Members": group.Members,
1500 "Action": group.Action,
1501 }).Debug("received PerformGroupOperation")
1502 return &openolt.Empty{}, nil
1503}
1504
1505func (o *OltDevice) DeleteGroup(ctx context.Context, group *openolt.Group) (*openolt.Empty, error) {
1506 oltLogger.WithFields(log.Fields{
1507 "GroupId": group.GroupId,
1508 "Command": group.Command,
1509 "Members": group.Members,
1510 "Action": group.Action,
1511 }).Debug("received PerformGroupOperation")
1512 return &openolt.Empty{}, nil
1513}
1514
1515func (o *OltDevice) GetExtValue(ctx context.Context, in *openolt.ValueParam) (*common_protos.ReturnValues, error) {
1516 return &common_protos.ReturnValues{}, nil
1517}
1518
1519func (o *OltDevice) OnuItuPonAlarmSet(ctx context.Context, in *config.OnuItuPonAlarm) (*openolt.Empty, error) {
1520 return &openolt.Empty{}, nil
1521}
1522
1523func (o *OltDevice) GetLogicalOnuDistanceZero(ctx context.Context, in *openolt.Onu) (*openolt.OnuLogicalDistance, error) {
1524 return &openolt.OnuLogicalDistance{}, nil
1525}
1526
1527func (o *OltDevice) GetLogicalOnuDistance(ctx context.Context, in *openolt.Onu) (*openolt.OnuLogicalDistance, error) {
1528 return &openolt.OnuLogicalDistance{}, nil
1529}