blob: 016f14835f0750bd3ba41337b12d436a813286d9 [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"
21 "errors"
22 "fmt"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020023 "net"
24 "sync"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010025 "time"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020026
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070027 "github.com/google/gopacket"
28 "github.com/google/gopacket/layers"
Matteo Scandolodf3f85d2020-01-15 12:50:48 -080029 "github.com/google/gopacket/pcap"
Matteo Scandolo4747d292019-08-05 11:50:18 -070030 "github.com/looplab/fsm"
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070031 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070032 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +010033 "github.com/opencord/bbsim/internal/common"
William Kurkian9dadc5b2019-10-22 13:51:57 -040034 omcisim "github.com/opencord/omci-sim"
Matteo Scandolo3de9de02019-11-14 13:40:03 -080035 "github.com/opencord/voltha-protos/v2/go/openolt"
36 "github.com/opencord/voltha-protos/v2/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070037 log "github.com/sirupsen/logrus"
38 "google.golang.org/grpc"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010039 "google.golang.org/grpc/reflection"
Matteo Scandolo4747d292019-08-05 11:50:18 -070040)
41
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070042var oltLogger = log.WithFields(log.Fields{
Matteo Scandolo84f7d482019-08-08 19:00:47 -070043 "module": "OLT",
44})
45
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070046type OltDevice struct {
David Bainbridge103cf022019-12-16 20:11:35 +000047 sync.Mutex
48
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070049 // BBSIM Internals
Matteo Scandoloe60a5052020-02-07 00:31:14 +000050 ID int
51 SerialNumber string
52 NumNni int
53 NumPon int
54 NumOnuPerPon int
55 InternalState *fsm.FSM
56 channel chan Message
57 nniPktInChannel chan *bbsim.PacketMsg // packets coming in from the NNI and going to VOLTHA
58 nniHandle *pcap.Handle // handle on the NNI interface, close it when shutting down the NNI channel
59
60 Delay int
Matteo Scandoloe33447a2019-10-31 12:38:23 -070061
Matteo Scandolo27428702019-10-11 16:21:16 -070062 Pons []*PonPort
63 Nnis []*NniPort
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070064
65 // OLT Attributes
66 OperState *fsm.FSM
David Bainbridge103cf022019-12-16 20:11:35 +000067
68 enableContext context.Context
69 enableContextCancel context.CancelFunc
Pragya Arya1cbefa42020-01-13 12:15:29 +053070
71 OpenoltStream *openolt.Openolt_EnableIndicationServer
Matteo Scandolo4747d292019-08-05 11:50:18 -070072}
73
Matteo Scandolo27428702019-10-11 16:21:16 -070074var olt OltDevice
Zdravko Bozakov681364d2019-11-10 14:28:46 +010075var oltServer *grpc.Server
Matteo Scandolo84f7d482019-08-08 19:00:47 -070076
Matteo Scandolo27428702019-10-11 16:21:16 -070077func GetOLT() *OltDevice {
78 return &olt
Matteo Scandolo84f7d482019-08-08 19:00:47 -070079}
80
Matteo Scandoloe60a5052020-02-07 00:31:14 +000081func CreateOLT(oltId int, nni int, pon int, onuPerPon int, sTag int, cTagInit int, auth bool, dhcp bool, delay int, isMock bool) *OltDevice {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070082 oltLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070083 "ID": oltId,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070084 "NumNni": nni,
85 "NumPon": pon,
86 "NumOnuPerPon": onuPerPon,
Matteo Scandolo4747d292019-08-05 11:50:18 -070087 }).Debug("CreateOLT")
88
Matteo Scandolo84f7d482019-08-08 19:00:47 -070089 olt = OltDevice{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070090 ID: oltId,
91 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", oltId),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070092 OperState: getOperStateFSM(func(e *fsm.Event) {
93 oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
94 }),
Zdravko Bozakov681364d2019-11-10 14:28:46 +010095 NumNni: nni,
96 NumPon: pon,
97 NumOnuPerPon: onuPerPon,
98 Pons: []*PonPort{},
99 Nnis: []*NniPort{},
100 Delay: delay,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700101 }
102
103 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700104 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700105 olt.InternalState = fsm.NewFSM(
106 "created",
107 fsm.Events{
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800108 {Name: "initialize", Src: []string{"created", "deleted"}, Dst: "initialized"},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100109 {Name: "enable", Src: []string{"initialized", "disabled"}, Dst: "enabled"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700110 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
Mahir Gunyel6dad4452020-01-06 12:59:04 -0800111 //delete event in enabled state below is for reboot OLT case.
112 {Name: "delete", Src: []string{"disabled", "enabled"}, Dst: "deleted"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700113 },
114 fsm.Callbacks{
115 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700116 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700117 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100118 "enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
Matteo Scandolo4747d292019-08-05 11:50:18 -0700119 },
120 )
121
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700122 if isMock != true {
123 // create NNI Port
124 nniPort, err := CreateNNI(&olt)
125 if err != nil {
126 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
127 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700128
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700129 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700130 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700131
Matteo Scandolo4747d292019-08-05 11:50:18 -0700132 // create PON ports
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700133 availableCTag := cTagInit
Matteo Scandolo4747d292019-08-05 11:50:18 -0700134 for i := 0; i < pon; i++ {
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000135 p := CreatePonPort(olt, uint32(i))
Matteo Scandolo4747d292019-08-05 11:50:18 -0700136
137 // create ONU devices
138 for j := 0; j < onuPerPon; j++ {
Pragya Arya1cbefa42020-01-13 12:15:29 +0530139 o := CreateONU(&olt, *p, uint32(j+1), sTag, availableCTag, auth, dhcp, isMock)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700140 p.Onus = append(p.Onus, o)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700141 availableCTag = availableCTag + 1
Matteo Scandolo4747d292019-08-05 11:50:18 -0700142 }
143
Pragya Arya6a708d62020-01-01 17:17:20 +0530144 olt.Pons = append(olt.Pons, p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700145 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100146
Matteo Scandolod32c3822019-11-26 15:57:46 -0700147 if isMock != true {
148 if err := olt.InternalState.Event("initialize"); err != nil {
149 log.Errorf("Error initializing OLT: %v", err)
150 return nil
151 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100152 }
153
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700154 return &olt
155}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700156
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100157func (o *OltDevice) InitOlt() error {
158
159 if oltServer == nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800160 oltServer, _ = o.newOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100161 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800162 // FIXME there should never be a server running if we are initializing the OLT
163 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100164 }
165
166 // create new channel for processOltMessages Go routine
167 o.channel = make(chan Message)
168
169 o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
170 // FIXME we are assuming we have only one NNI
171 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800172 // NOTE we want to make sure the state is down when we initialize the OLT,
173 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
174 // in-band management
175 o.Nnis[0].OperState.SetState("down")
176 ch, handle, err := o.Nnis[0].NewVethChan()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100177 if err == nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800178 oltLogger.WithFields(log.Fields{
179 "Type": o.Nnis[0].Type,
180 "IntfId": o.Nnis[0].ID,
181 "OperState": o.Nnis[0].OperState.Current(),
182 }).Info("NNI Channel created")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100183 o.nniPktInChannel = ch
Matteo Scandolo401503a2019-12-11 14:48:14 -0800184 o.nniHandle = handle
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100185 } else {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800186 oltLogger.Errorf("Error getting NNI channel: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100187 }
188 }
189
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100190 return nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700191}
192
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800193func (o *OltDevice) RestartOLT() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100194
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800195 rebootDelay := common.Options.Olt.OltRebootDelay
196
197 oltLogger.WithFields(log.Fields{
198 "oltId": o.ID,
199 }).Infof("Simulating OLT restart... (%ds)", rebootDelay)
200
201 // transition internal state to deleted
202 if err := o.InternalState.Event("delete"); err != nil {
203 oltLogger.WithFields(log.Fields{
204 "oltId": o.ID,
205 }).Errorf("Error deleting OLT: %v", err)
206 return err
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100207 }
208
209 // TODO handle hard poweroff (i.e. no indications sent to Voltha) vs soft poweroff
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800210 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
211 if err := o.StopOltServer(); err != nil {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100212 return err
213 }
214
215 // terminate the OLT's processOltMessages go routine
216 close(o.channel)
217 // terminate the OLT's processNniPacketIns go routine
Andy Bavier421f4d52020-01-21 15:39:22 -0700218 go o.nniHandle.Close()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100219 close(o.nniPktInChannel)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100220
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000221 for i := range olt.Pons {
222 for _, onu := range olt.Pons[i].Onus {
223 // NOTE while the olt is off, restore the ONU to the initial state
224 onu.InternalState.SetState("created")
225 }
226 }
227
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100228 time.Sleep(time.Duration(rebootDelay) * time.Second)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100229
230 if err := o.InternalState.Event("initialize"); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800231 oltLogger.WithFields(log.Fields{
232 "oltId": o.ID,
233 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100234 return err
235 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800236 oltLogger.WithFields(log.Fields{
237 "oltId": o.ID,
238 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100239 return nil
240}
241
242// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800243func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100244 address := common.Options.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700245 lis, err := net.Listen("tcp", address)
246 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700247 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700248 }
249 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100250
Matteo Scandolo4747d292019-08-05 11:50:18 -0700251 openolt.RegisterOpenoltServer(grpcServer, o)
252
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100253 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700254
Matteo Scandolo4747d292019-08-05 11:50:18 -0700255 go grpcServer.Serve(lis)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100256 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700257
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100258 return grpcServer, nil
259}
260
261// StopOltServer stops the OpenOLT grpc server
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800262func (o *OltDevice) StopOltServer() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100263 // TODO handle poweroff vs graceful shutdown
264 if oltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800265 oltLogger.WithFields(log.Fields{
266 "oltId": o.SerialNumber,
267 }).Warnf("Stopping OLT gRPC server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100268 oltServer.Stop()
269 oltServer = nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700270 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800271
Matteo Scandolo4747d292019-08-05 11:50:18 -0700272 return nil
273}
274
275// Device Methods
276
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100277// Enable implements the OpenOLT EnableIndicationServer functionality
278func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700279 oltLogger.Debug("Enable OLT called")
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700280
David Bainbridge103cf022019-12-16 20:11:35 +0000281 // If enabled has already been called then an enabled context has
282 // been created. If this is the case then we want to cancel all the
283 // proessing loops associated with that enable before we recreate
284 // new ones
285 o.Lock()
286 if o.enableContext != nil && o.enableContextCancel != nil {
287 o.enableContextCancel()
288 }
289 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
290 o.Unlock()
291
Matteo Scandolo4747d292019-08-05 11:50:18 -0700292 wg := sync.WaitGroup{}
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800293 wg.Add(3)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700294
Pragya Arya1cbefa42020-01-13 12:15:29 +0530295 o.OpenoltStream = &stream
296
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100297 // create Go routine to process all OLT events
David Bainbridge103cf022019-12-16 20:11:35 +0000298 go o.processOltMessages(o.enableContext, stream, &wg)
299 go o.processNniPacketIns(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700300
301 // enable the OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100302 oltMsg := Message{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700303 Type: OltIndication,
304 Data: OltIndicationMessage{
305 OperState: UP,
306 },
307 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100308 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700309
310 // send NNI Port Indications
311 for _, nni := range o.Nnis {
312 msg := Message{
313 Type: NniIndication,
314 Data: NniIndicationMessage{
315 OperState: UP,
316 NniPortID: nni.ID,
317 },
318 }
319 o.channel <- msg
320 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100321
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800322 go o.processOmciMessages(o.enableContext, stream, &wg)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100323
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000324 // send PON Port indications
325 for i, pon := range o.Pons {
326 msg := Message{
327 Type: PonIndication,
328 Data: PonIndicationMessage{
329 OperState: UP,
330 PonPortID: pon.ID,
331 },
Pragya Arya1881df02020-01-29 18:05:01 +0530332 }
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000333 o.channel <- msg
Pragya Arya1881df02020-01-29 18:05:01 +0530334
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000335 for _, onu := range o.Pons[i].Onus {
336 if err := onu.InternalState.Event("initialize"); err != nil {
337 log.Errorf("Error initializing ONU: %v", err)
338 continue
339 }
340 if err := onu.InternalState.Event("discover"); err != nil {
341 log.Errorf("Error discover ONU: %v", err)
342 return err
Matteo Scandolo4747d292019-08-05 11:50:18 -0700343 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700344 }
345 }
346
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800347 oltLogger.Debug("Enable OLT Done")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700348 wg.Wait()
349 return nil
350}
351
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800352func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400353 ch := omcisim.GetChannel()
354
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100355 oltLogger.Debug("Starting OMCI Indication Channel")
William Kurkian9dadc5b2019-10-22 13:51:57 -0400356
David Bainbridge103cf022019-12-16 20:11:35 +0000357loop:
358 for {
359 select {
360 case <-ctx.Done():
361 oltLogger.Debug("OMCI processing canceled via context")
362 break loop
363 case message, ok := <-ch:
364 if !ok || ctx.Err() != nil {
365 oltLogger.Debug("OMCI processing canceled via channel close")
366 break loop
367 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800368
369 oltLogger.WithFields(log.Fields{
370 "messageType": message.Type,
371 "OnuId": message.Data.OnuId,
372 "IntfId": message.Data.IntfId,
373 }).Info("Received message on OMCI Sim channel")
374
David Bainbridge103cf022019-12-16 20:11:35 +0000375 onuId := message.Data.OnuId
376 intfId := message.Data.IntfId
377 onu, err := o.FindOnuById(intfId, onuId)
378 if err != nil {
379 oltLogger.Errorf("Failed to find onu: %v", err)
380 continue
381 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800382 go onu.processOmciMessage(message, stream)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400383 }
William Kurkian9dadc5b2019-10-22 13:51:57 -0400384 }
David Bainbridge103cf022019-12-16 20:11:35 +0000385
386 wg.Done()
William Kurkian9dadc5b2019-10-22 13:51:57 -0400387}
388
Matteo Scandolo4747d292019-08-05 11:50:18 -0700389// Helpers method
390
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700391func (o OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700392 for _, pon := range o.Pons {
393 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700394 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700395 }
396 }
397 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
398}
399
400func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
401 for _, nni := range o.Nnis {
402 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700403 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700404 }
405 }
406 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
407}
408
Scott Baker41724b82020-01-21 19:54:53 -0800409func (o *OltDevice) sendAlarmIndication(alarmInd *openolt.AlarmIndication, stream openolt.Openolt_EnableIndicationServer) {
410 data := &openolt.Indication_AlarmInd{AlarmInd: alarmInd}
411 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
412 oltLogger.Errorf("Failed to send Alarm Indication: %v", err)
413 return
414 }
415
416 oltLogger.WithFields(log.Fields{
417 "AlarmIndication": alarmInd,
418 }).Debug("Sent Indication_AlarmInd")
419}
420
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100421func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700422 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
423 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700424 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800425 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700426 }
427
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700428 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700429 "OperState": msg.OperState,
430 }).Debug("Sent Indication_OltInd")
431}
432
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100433func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700434 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800435 if msg.OperState == UP {
436 if err := nni.OperState.Event("enable"); err != nil {
437 log.WithFields(log.Fields{
438 "Type": nni.Type,
439 "IntfId": nni.ID,
440 "OperState": nni.OperState.Current(),
441 }).Errorf("Can't move NNI Port to enabled state: %v", err)
442 }
443 } else if msg.OperState == DOWN {
444 if err := nni.OperState.Event("disable"); err != nil {
445 log.WithFields(log.Fields{
446 "Type": nni.Type,
447 "IntfId": nni.ID,
448 "OperState": nni.OperState.Current(),
449 }).Errorf("Can't move NNI Port to disable state: %v", err)
450 }
451 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700452 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700453 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700454 Type: nni.Type,
455 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700456 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700457 }}
458
459 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700460 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800461 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700462 }
463
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700464 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700465 "Type": nni.Type,
466 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700467 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700468 }).Debug("Sent Indication_IntfOperInd for NNI")
469}
470
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000471func (o *OltDevice) sendPonIndication(msg PonIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
472 pon, _ := o.GetPonById(msg.PonPortID)
473 if msg.OperState == UP {
474 if err := pon.OperState.Event("enable"); err != nil {
475 log.WithFields(log.Fields{
476 "Type": pon.Type,
477 "IntfId": pon.ID,
478 "OperState": pon.OperState.Current(),
479 }).Errorf("Can't move PON Port to enable state: %v", err)
480 }
481 } else if msg.OperState == DOWN {
482 if err := pon.OperState.Event("disable"); err != nil {
483 log.WithFields(log.Fields{
484 "Type": pon.Type,
485 "IntfId": pon.ID,
486 "OperState": pon.OperState.Current(),
487 }).Errorf("Can't move PON Port to disable state: %v", err)
488 }
489 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700490 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700491 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700492 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700493 }}
494
495 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700496 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800497 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700498 }
499
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700500 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700501 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700502 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700503 }).Debug("Sent Indication_IntfInd")
504
505 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700506 Type: pon.Type,
507 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700508 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700509 }}
510
511 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700512 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800513 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700514 }
515
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700516 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700517 "Type": pon.Type,
518 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700519 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700520 }).Debug("Sent Indication_IntfOperInd for PON")
521}
522
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100523// processOltMessages handles messages received over the OpenOLT interface
David Bainbridge103cf022019-12-16 20:11:35 +0000524func (o *OltDevice) processOltMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100525 oltLogger.Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000526 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700527
David Bainbridge103cf022019-12-16 20:11:35 +0000528loop:
529 for {
530 select {
531 case <-ctx.Done():
532 oltLogger.Debug("OLT Indication processing canceled via context")
533 break loop
534 case message, ok := <-ch:
535 if !ok || ctx.Err() != nil {
536 oltLogger.Debug("OLT Indication processing canceled via closed channel")
537 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700538 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700539
David Bainbridge103cf022019-12-16 20:11:35 +0000540 oltLogger.WithFields(log.Fields{
541 "oltId": o.ID,
542 "messageType": message.Type,
543 }).Trace("Received message")
544
545 switch message.Type {
546 case OltIndication:
547 msg, _ := message.Data.(OltIndicationMessage)
548 if msg.OperState == UP {
549 o.InternalState.Event("enable")
550 o.OperState.Event("enable")
551 } else if msg.OperState == DOWN {
552 o.InternalState.Event("disable")
553 o.OperState.Event("disable")
554 }
555 o.sendOltIndication(msg, stream)
Scott Baker41724b82020-01-21 19:54:53 -0800556 case AlarmIndication:
557 alarmInd, _ := message.Data.(*openolt.AlarmIndication)
558 o.sendAlarmIndication(alarmInd, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000559 case NniIndication:
560 msg, _ := message.Data.(NniIndicationMessage)
561 o.sendNniIndication(msg, stream)
562 case PonIndication:
563 msg, _ := message.Data.(PonIndicationMessage)
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000564 o.sendPonIndication(msg, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000565 default:
566 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
567 }
568 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700569 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100570 wg.Done()
571 oltLogger.Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700572}
573
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100574// processNniPacketIns handles messages received over the NNI interface
David Bainbridge103cf022019-12-16 20:11:35 +0000575func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700576 oltLogger.WithFields(log.Fields{
577 "nniChannel": o.nniPktInChannel,
Matteo Scandolo401503a2019-12-11 14:48:14 -0800578 }).Debug("Started Processing Packets arriving from the NNI")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700579 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700580
David Bainbridge103cf022019-12-16 20:11:35 +0000581 ch := o.nniPktInChannel
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700582
David Bainbridge103cf022019-12-16 20:11:35 +0000583loop:
584 for {
585 select {
586 case <-ctx.Done():
587 oltLogger.Debug("NNI Indication processing canceled via context")
588 break loop
589 case message, ok := <-ch:
590 if !ok || ctx.Err() != nil {
591 oltLogger.Debug("NNI Indication processing canceled via channel closed")
592 break loop
593 }
594 oltLogger.Tracef("Received packets on NNI Channel")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700595
David Bainbridge103cf022019-12-16 20:11:35 +0000596 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700597
David Bainbridge103cf022019-12-16 20:11:35 +0000598 if err != nil {
599 log.WithFields(log.Fields{
600 "IntfType": "nni",
601 "IntfId": nniId,
602 "Pkt": message.Pkt.Data(),
603 }).Error("Can't find Dst MacAddress in packet")
604 return
605 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700606
David Bainbridge103cf022019-12-16 20:11:35 +0000607 onu, err := o.FindOnuByMacAddress(onuMac)
608 if err != nil {
609 log.WithFields(log.Fields{
610 "IntfType": "nni",
611 "IntfId": nniId,
612 "Pkt": message.Pkt.Data(),
613 "MacAddress": onuMac.String(),
614 }).Error("Can't find ONU with MacAddress")
615 return
616 }
617
618 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
619 if err != nil {
620 log.Error("Fail to add double tag to packet")
621 }
622
623 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
624 IntfType: "nni",
625 IntfId: nniId,
626 Pkt: doubleTaggedPkt.Data()}}
627 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
628 oltLogger.WithFields(log.Fields{
629 "IntfType": data.PktInd.IntfType,
630 "IntfId": nniId,
631 "Pkt": doubleTaggedPkt.Data(),
632 }).Errorf("Fail to send PktInd indication: %v", err)
633 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700634 oltLogger.WithFields(log.Fields{
635 "IntfType": data.PktInd.IntfType,
636 "IntfId": nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700637 "Pkt": doubleTaggedPkt.Data(),
David Bainbridge103cf022019-12-16 20:11:35 +0000638 "OnuSn": onu.Sn(),
639 }).Tracef("Sent PktInd indication")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700640 }
641 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100642 wg.Done()
643 oltLogger.WithFields(log.Fields{
644 "nniChannel": o.nniPktInChannel,
645 }).Warn("Stopped handling NNI Channel")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700646}
647
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000648func (o *OltDevice) handleReenableOlt() {
649 // enable OLT
650 oltMsg := Message{
651 Type: OltIndication,
652 Data: OltIndicationMessage{
653 OperState: UP,
654 },
655 }
656 o.channel <- oltMsg
657
658 for i := range olt.Pons {
659 for _, onu := range olt.Pons[i].Onus {
660 if err := onu.InternalState.Event("discover"); err != nil {
661 log.Errorf("Error discover ONU: %v", err)
662 }
663 }
664 }
665
666}
667
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700668// returns an ONU with a given Serial Number
669func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200670 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700671 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700672 for _, pon := range o.Pons {
673 for _, onu := range pon.Onus {
674 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700675 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700676 }
677 }
678 }
679
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700680 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-serial-number-%s", serialNumber))
681}
682
William Kurkian9dadc5b2019-10-22 13:51:57 -0400683// returns an ONU with a given interface/Onu Id
684func (o OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200685 // TODO this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400686 // memoizing it will remove the bottleneck
687 for _, pon := range o.Pons {
688 if pon.ID == intfId {
689 for _, onu := range pon.Onus {
690 if onu.ID == onuId {
691 return onu, nil
692 }
693 }
694 }
695 }
696 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-id-%v-%v", intfId, onuId))
697}
698
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700699// returns an ONU with a given Mac Address
700func (o OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200701 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700702 // memoizing it will remove the bottleneck
703 for _, pon := range o.Pons {
704 for _, onu := range pon.Onus {
705 if onu.HwAddress.String() == mac.String() {
Matteo Scandolo27428702019-10-11 16:21:16 -0700706 return onu, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700707 }
708 }
709 }
710
711 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-mac-address-%s", mac))
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700712}
713
Matteo Scandolo4747d292019-08-05 11:50:18 -0700714// GRPC Endpoints
715
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700716func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700717 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700718 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700719 }).Info("Received ActivateOnu call from VOLTHA")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700720
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700721 pon, _ := o.GetPonById(onu.IntfId)
722 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
William Kurkian0418bc82019-11-06 12:16:24 -0500723 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700724
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700725 if err := _onu.OperState.Event("enable"); err != nil {
726 oltLogger.WithFields(log.Fields{
727 "IntfId": _onu.PonPortID,
728 "OnuSn": _onu.Sn(),
729 "OnuId": _onu.ID,
730 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700731 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700732 if err := _onu.InternalState.Event("enable"); err != nil {
733 oltLogger.WithFields(log.Fields{
734 "IntfId": _onu.PonPortID,
735 "OnuSn": _onu.Sn(),
736 "OnuId": _onu.ID,
737 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
738 }
739
740 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
741
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700742 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700743}
744
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700745func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700746 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700747 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700748}
749
Pragya Arya1cbefa42020-01-13 12:15:29 +0530750func (o OltDevice) DeleteOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
751 oltLogger.WithFields(log.Fields{
752 "IntfId": onu.IntfId,
753 "OnuId": onu.OnuId,
754 }).Info("Received DeleteOnu call from VOLTHA")
755
756 pon, err := o.GetPonById(onu.IntfId)
757 if err != nil {
758 oltLogger.WithFields(log.Fields{
759 "OnuId": onu.OnuId,
760 "IntfId": onu.IntfId,
761 "err": err,
762 }).Error("Can't find PonPort")
763 }
764 _onu, err := pon.GetOnuById(onu.OnuId)
765 if err != nil {
766 oltLogger.WithFields(log.Fields{
767 "OnuId": onu.OnuId,
768 "IntfId": onu.IntfId,
769 "err": err,
770 }).Error("Can't find Onu")
771 }
772
773 if err := _onu.InternalState.Event("initialize"); err != nil {
774 oltLogger.WithFields(log.Fields{
775 "IntfId": _onu.PonPortID,
776 "OnuSn": _onu.Sn(),
777 "OnuId": _onu.ID,
778 }).Infof("Failed to transition ONU to initialized state: %s", err.Error())
779 }
780
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700781 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700782}
783
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700784func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700785 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800786 oltLogger.WithFields(log.Fields{
787 "oltId": o.ID,
788 }).Info("Disabling OLT")
789
Matteo Scandolo401503a2019-12-11 14:48:14 -0800790 for _, pon := range o.Pons {
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000791 // disable PONs
792 msg := Message{
793 Type: PonIndication,
794 Data: PonIndicationMessage{
795 OperState: DOWN,
796 PonPortID: pon.ID,
797 },
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800798 }
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000799
800 o.channel <- msg
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800801 }
802
Matteo Scandolo401503a2019-12-11 14:48:14 -0800803 // Note that we are not disabling the NNI as the real OLT does not.
804 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800805
806 // disable OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100807 oltMsg := Message{
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700808 Type: OltIndication,
809 Data: OltIndicationMessage{
810 OperState: DOWN,
811 },
812 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100813 o.channel <- oltMsg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700814 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700815}
816
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700817func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700818 oltLogger.Error("DisablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700819 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700820}
821
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100822func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700823 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700824 o.Enable(stream)
825 return nil
826}
827
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000828func (o OltDevice) EnablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
829 oltLogger.Error("EnablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700830 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700831}
832
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700833func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700834 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700835 "IntfId": flow.AccessIntfId,
836 "OnuId": flow.OnuId,
837 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700838 "InnerVlan": flow.Classifier.IVid,
839 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700840 "FlowType": flow.FlowType,
841 "FlowId": flow.FlowId,
842 "UniID": flow.UniId,
843 "PortNo": flow.PortNo,
844 }).Tracef("OLT receives Flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700845 // TODO optionally store flows somewhere
846
847 if flow.AccessIntfId == -1 {
848 oltLogger.WithFields(log.Fields{
849 "FlowId": flow.FlowId,
850 }).Debugf("This is an OLT flow")
851 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700852 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700853 if err != nil {
854 oltLogger.WithFields(log.Fields{
855 "OnuId": flow.OnuId,
856 "IntfId": flow.AccessIntfId,
857 "err": err,
858 }).Error("Can't find PonPort")
859 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700860 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700861 if err != nil {
862 oltLogger.WithFields(log.Fields{
863 "OnuId": flow.OnuId,
864 "IntfId": flow.AccessIntfId,
865 "err": err,
866 }).Error("Can't find Onu")
867 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700868
869 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700870 Type: FlowUpdate,
871 Data: OnuFlowUpdateMessage{
872 PonPortID: pon.ID,
873 OnuID: onu.ID,
874 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700875 },
876 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700877 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700878 }
879
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700880 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700881}
882
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700883func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
884 oltLogger.Tracef("received FlowRemove")
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700885 // TODO store flows somewhere
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700886 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700887}
888
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700889func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo18859852020-01-15 13:33:57 -0800890 res := openolt.Heartbeat{HeartbeatSignature: uint32(time.Now().Unix())}
891 oltLogger.WithFields(log.Fields{
892 "signature": res.HeartbeatSignature,
893 }).Trace("HeartbeatCheck")
894 return &res, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700895}
896
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700897func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700898
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700899 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700900 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700901 "PonPorts": o.NumPon,
902 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700903 devinfo := new(openolt.DeviceInfo)
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100904 devinfo.Vendor = common.Options.Olt.Vendor
905 devinfo.Model = common.Options.Olt.Model
906 devinfo.HardwareVersion = common.Options.Olt.HardwareVersion
907 devinfo.FirmwareVersion = common.Options.Olt.FirmwareVersion
908 devinfo.Technology = common.Options.Olt.Technology
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700909 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700910 devinfo.OnuIdStart = 1
911 devinfo.OnuIdEnd = 255
912 devinfo.AllocIdStart = 1024
913 devinfo.AllocIdEnd = 16383
914 devinfo.GemportIdStart = 1024
915 devinfo.GemportIdEnd = 65535
916 devinfo.FlowIdStart = 1
917 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -0700918 devinfo.DeviceSerialNumber = o.SerialNumber
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100919 devinfo.DeviceId = common.Options.Olt.DeviceId
Matteo Scandolo4747d292019-08-05 11:50:18 -0700920
921 return devinfo, nil
922}
923
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700924func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700925 pon, _ := o.GetPonById(omci_msg.IntfId)
926 onu, _ := pon.GetOnuById(omci_msg.OnuId)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700927 oltLogger.WithFields(log.Fields{
928 "IntfId": onu.PonPortID,
929 "OnuId": onu.ID,
930 "OnuSn": onu.Sn(),
931 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700932 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700933 Type: OMCI,
934 Data: OmciMessage{
935 OnuSN: onu.SerialNumber,
936 OnuID: onu.ID,
937 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700938 },
939 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700940 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700941 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700942}
943
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700944func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700945 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700946 if err != nil {
947 oltLogger.WithFields(log.Fields{
948 "OnuId": onuPkt.OnuId,
949 "IntfId": onuPkt.IntfId,
950 "err": err,
951 }).Error("Can't find PonPort")
952 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700953 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700954 if err != nil {
955 oltLogger.WithFields(log.Fields{
956 "OnuId": onuPkt.OnuId,
957 "IntfId": onuPkt.IntfId,
958 "err": err,
959 }).Error("Can't find Onu")
960 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700961
Matteo Scandolo075b1892019-10-07 12:11:07 -0700962 oltLogger.WithFields(log.Fields{
963 "IntfId": onu.PonPortID,
964 "OnuId": onu.ID,
965 "OnuSn": onu.Sn(),
966 }).Tracef("Received OnuPacketOut")
967
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700968 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700969 pktType, err := packetHandlers.IsEapolOrDhcp(rawpkt)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700970
Matteo Scandolo075b1892019-10-07 12:11:07 -0700971 msg := Message{
972 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700973 Data: OnuPacketMessage{
Matteo Scandolo075b1892019-10-07 12:11:07 -0700974 IntfId: onuPkt.IntfId,
975 OnuId: onuPkt.OnuId,
976 Packet: rawpkt,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700977 Type: pktType,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700978 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700979 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700980 onu.Channel <- msg
981
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700982 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700983}
984
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700985func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800986 oltLogger.WithFields(log.Fields{
987 "oltId": o.ID,
988 }).Info("Shutting down")
989 go o.RestartOLT()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700990 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700991}
992
993func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Pragya Arya6a708d62020-01-01 17:17:20 +0530994 oltLogger.WithFields(log.Fields{
995 "oltId": o.ID,
996 }).Info("Received ReenableOlt request from VOLTHA")
997
Pragya Arya1881df02020-01-29 18:05:01 +0530998 for _, pon := range o.Pons {
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000999 msg := Message{
1000 Type: PonIndication,
1001 Data: PonIndicationMessage{
1002 OperState: UP,
1003 PonPortID: pon.ID,
1004 },
Pragya Arya1881df02020-01-29 18:05:01 +05301005 }
Matteo Scandoloe60a5052020-02-07 00:31:14 +00001006 o.channel <- msg
Pragya Arya1881df02020-01-29 18:05:01 +05301007 }
Pragya Arya6a708d62020-01-01 17:17:20 +05301008
Matteo Scandoloe60a5052020-02-07 00:31:14 +00001009 // Openolt adapter will start processing indications only after success reponse of ReenableOlt
1010 // thats why need to send OLT and ONU indications after return of this function
1011 go o.handleReenableOlt()
1012
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001013 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001014}
1015
1016func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001017 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
1018
Zdravko Bozakov681364d2019-11-10 14:28:46 +01001019 o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001020 // NOTE should we return an error if sendNniPakcet fails?
1021 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001022}
1023
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001024func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001025 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001026 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001027}
1028
Matteo Scandolo4747d292019-08-05 11:50:18 -07001029func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001030 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001031 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001032}
1033
1034func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001035 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001036 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -07001037}
1038
1039func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001040 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001041 return new(openolt.Empty), nil
1042}
1043
1044func (s OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001045 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001046 return new(openolt.Empty), nil
1047}
1048
1049func (s OltDevice) CreateTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001050 oltLogger.Info("received CreateTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001051 return new(openolt.Empty), nil
1052}
1053
1054func (s OltDevice) RemoveTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001055 oltLogger.Info("received RemoveTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001056 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001057}
Scott Baker41724b82020-01-21 19:54:53 -08001058
1059// assumes caller has properly formulated an openolt.AlarmIndication
1060func (o OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
1061 msg := Message{
1062 Type: AlarmIndication,
1063 Data: ind,
1064 }
1065
1066 o.channel <- msg
1067 return nil
1068}