blob: e5ed6bccc6964b20112c570dbc257a6419c89309 [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
50 ID int
51 SerialNumber string
52 NumNni int
53 NumPon int
54 NumOnuPerPon int
55 InternalState *fsm.FSM
56 channel chan Message
Zdravko Bozakov681364d2019-11-10 14:28:46 +010057 nniPktInChannel chan *bbsim.PacketMsg // packets coming in from the NNI and going to VOLTHA
Matteo Scandolo401503a2019-12-11 14:48:14 -080058 nniHandle *pcap.Handle // handle on the NNI interface, close it when shutting down the NNI channel
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070059
Matteo Scandoloe33447a2019-10-31 12:38:23 -070060 Delay int
61
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
Matteo Scandolo4747d292019-08-05 11:50:18 -070070}
71
Matteo Scandolo27428702019-10-11 16:21:16 -070072var olt OltDevice
Zdravko Bozakov681364d2019-11-10 14:28:46 +010073var oltServer *grpc.Server
Matteo Scandolo84f7d482019-08-08 19:00:47 -070074
Matteo Scandolo27428702019-10-11 16:21:16 -070075func GetOLT() *OltDevice {
76 return &olt
Matteo Scandolo84f7d482019-08-08 19:00:47 -070077}
78
Zdravko Bozakov681364d2019-11-10 14:28:46 +010079func 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 -070080 oltLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070081 "ID": oltId,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070082 "NumNni": nni,
83 "NumPon": pon,
84 "NumOnuPerPon": onuPerPon,
Matteo Scandolo4747d292019-08-05 11:50:18 -070085 }).Debug("CreateOLT")
86
Matteo Scandolo84f7d482019-08-08 19:00:47 -070087 olt = OltDevice{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070088 ID: oltId,
89 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", oltId),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070090 OperState: getOperStateFSM(func(e *fsm.Event) {
91 oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
92 }),
Zdravko Bozakov681364d2019-11-10 14:28:46 +010093 NumNni: nni,
94 NumPon: pon,
95 NumOnuPerPon: onuPerPon,
96 Pons: []*PonPort{},
97 Nnis: []*NniPort{},
98 Delay: delay,
Matteo Scandolo4747d292019-08-05 11:50:18 -070099 }
100
101 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700102 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700103 olt.InternalState = fsm.NewFSM(
104 "created",
105 fsm.Events{
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800106 {Name: "initialize", Src: []string{"created", "deleted"}, Dst: "initialized"},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100107 {Name: "enable", Src: []string{"initialized", "disabled"}, Dst: "enabled"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700108 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
Mahir Gunyel6dad4452020-01-06 12:59:04 -0800109 //delete event in enabled state below is for reboot OLT case.
110 {Name: "delete", Src: []string{"disabled", "enabled"}, Dst: "deleted"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700111 },
112 fsm.Callbacks{
113 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700114 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700115 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100116 "enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
Matteo Scandolo4747d292019-08-05 11:50:18 -0700117 },
118 )
119
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700120 if isMock != true {
121 // create NNI Port
122 nniPort, err := CreateNNI(&olt)
123 if err != nil {
124 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
125 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700126
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700127 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700128 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700129
Matteo Scandolo4747d292019-08-05 11:50:18 -0700130 // create PON ports
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700131 availableCTag := cTagInit
Matteo Scandolo4747d292019-08-05 11:50:18 -0700132 for i := 0; i < pon; i++ {
Pragya Arya6a708d62020-01-01 17:17:20 +0530133 p := CreatePonPort(olt, uint32(i))
Matteo Scandolo4747d292019-08-05 11:50:18 -0700134
135 // create ONU devices
136 for j := 0; j < onuPerPon; j++ {
Pragya Arya6a708d62020-01-01 17:17:20 +0530137 o := CreateONU(olt, *p, uint32(j+1), sTag, availableCTag, auth, dhcp)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700138 p.Onus = append(p.Onus, o)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700139 availableCTag = availableCTag + 1
Matteo Scandolo4747d292019-08-05 11:50:18 -0700140 }
141
Pragya Arya6a708d62020-01-01 17:17:20 +0530142 olt.Pons = append(olt.Pons, p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700143 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100144
Matteo Scandolod32c3822019-11-26 15:57:46 -0700145 if isMock != true {
146 if err := olt.InternalState.Event("initialize"); err != nil {
147 log.Errorf("Error initializing OLT: %v", err)
148 return nil
149 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100150 }
151
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700152 return &olt
153}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700154
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100155func (o *OltDevice) InitOlt() error {
156
157 if oltServer == nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800158 oltServer, _ = o.newOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100159 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800160 // FIXME there should never be a server running if we are initializing the OLT
161 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100162 }
163
164 // create new channel for processOltMessages Go routine
165 o.channel = make(chan Message)
166
167 o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
168 // FIXME we are assuming we have only one NNI
169 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800170 // NOTE we want to make sure the state is down when we initialize the OLT,
171 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
172 // in-band management
173 o.Nnis[0].OperState.SetState("down")
174 ch, handle, err := o.Nnis[0].NewVethChan()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100175 if err == nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800176 oltLogger.WithFields(log.Fields{
177 "Type": o.Nnis[0].Type,
178 "IntfId": o.Nnis[0].ID,
179 "OperState": o.Nnis[0].OperState.Current(),
180 }).Info("NNI Channel created")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100181 o.nniPktInChannel = ch
Matteo Scandolo401503a2019-12-11 14:48:14 -0800182 o.nniHandle = handle
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100183 } else {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800184 oltLogger.Errorf("Error getting NNI channel: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100185 }
186 }
187
188 for i := range olt.Pons {
189 for _, onu := range olt.Pons[i].Onus {
190 if err := onu.InternalState.Event("initialize"); err != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800191 oltLogger.Errorf("Error initializing ONU: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100192 return err
193 }
194 }
195 }
196
197 return nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700198}
199
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800200func (o *OltDevice) RestartOLT() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100201
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800202 rebootDelay := common.Options.Olt.OltRebootDelay
203
204 oltLogger.WithFields(log.Fields{
205 "oltId": o.ID,
206 }).Infof("Simulating OLT restart... (%ds)", rebootDelay)
207
208 // transition internal state to deleted
209 if err := o.InternalState.Event("delete"); err != nil {
210 oltLogger.WithFields(log.Fields{
211 "oltId": o.ID,
212 }).Errorf("Error deleting OLT: %v", err)
213 return err
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100214 }
215
216 // TODO handle hard poweroff (i.e. no indications sent to Voltha) vs soft poweroff
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800217 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
218 if err := o.StopOltServer(); err != nil {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100219 return err
220 }
221
222 // terminate the OLT's processOltMessages go routine
223 close(o.channel)
224 // terminate the OLT's processNniPacketIns go routine
Andy Bavier421f4d52020-01-21 15:39:22 -0700225 go o.nniHandle.Close()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100226 close(o.nniPktInChannel)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100227
Matteo Scandolo401503a2019-12-11 14:48:14 -0800228 for i := range olt.Pons {
229 for _, onu := range olt.Pons[i].Onus {
230 // NOTE while the olt is off, restore the ONU to the initial state
231 onu.InternalState.SetState("created")
232 }
233 }
234
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100235 time.Sleep(time.Duration(rebootDelay) * time.Second)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100236
237 if err := o.InternalState.Event("initialize"); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800238 oltLogger.WithFields(log.Fields{
239 "oltId": o.ID,
240 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100241 return err
242 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800243 oltLogger.WithFields(log.Fields{
244 "oltId": o.ID,
245 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100246 return nil
247}
248
249// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800250func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100251 address := common.Options.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700252 lis, err := net.Listen("tcp", address)
253 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700254 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700255 }
256 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100257
Matteo Scandolo4747d292019-08-05 11:50:18 -0700258 openolt.RegisterOpenoltServer(grpcServer, o)
259
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100260 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700261
Matteo Scandolo4747d292019-08-05 11:50:18 -0700262 go grpcServer.Serve(lis)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100263 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700264
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100265 return grpcServer, nil
266}
267
268// StopOltServer stops the OpenOLT grpc server
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800269func (o *OltDevice) StopOltServer() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100270 // TODO handle poweroff vs graceful shutdown
271 if oltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800272 oltLogger.WithFields(log.Fields{
273 "oltId": o.SerialNumber,
274 }).Warnf("Stopping OLT gRPC server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100275 oltServer.Stop()
276 oltServer = nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700277 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800278
Matteo Scandolo4747d292019-08-05 11:50:18 -0700279 return nil
280}
281
282// Device Methods
283
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100284// Enable implements the OpenOLT EnableIndicationServer functionality
285func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700286 oltLogger.Debug("Enable OLT called")
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700287
David Bainbridge103cf022019-12-16 20:11:35 +0000288 // If enabled has already been called then an enabled context has
289 // been created. If this is the case then we want to cancel all the
290 // proessing loops associated with that enable before we recreate
291 // new ones
292 o.Lock()
293 if o.enableContext != nil && o.enableContextCancel != nil {
294 o.enableContextCancel()
295 }
296 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
297 o.Unlock()
298
Matteo Scandolo4747d292019-08-05 11:50:18 -0700299 wg := sync.WaitGroup{}
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800300 wg.Add(3)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700301
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100302 // create Go routine to process all OLT events
David Bainbridge103cf022019-12-16 20:11:35 +0000303 go o.processOltMessages(o.enableContext, stream, &wg)
304 go o.processNniPacketIns(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700305
306 // enable the OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100307 oltMsg := Message{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700308 Type: OltIndication,
309 Data: OltIndicationMessage{
310 OperState: UP,
311 },
312 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100313 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700314
315 // send NNI Port Indications
316 for _, nni := range o.Nnis {
317 msg := Message{
318 Type: NniIndication,
319 Data: NniIndicationMessage{
320 OperState: UP,
321 NniPortID: nni.ID,
322 },
323 }
324 o.channel <- msg
325 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100326
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800327 go o.processOmciMessages(o.enableContext, stream, &wg)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100328
Matteo Scandolo4747d292019-08-05 11:50:18 -0700329 // send PON Port indications
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100330 for i, pon := range o.Pons {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700331 msg := Message{
332 Type: PonIndication,
333 Data: PonIndicationMessage{
334 OperState: UP,
335 PonPortID: pon.ID,
336 },
337 }
338 o.channel <- msg
339
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100340 for _, onu := range o.Pons[i].Onus {
David Bainbridge103cf022019-12-16 20:11:35 +0000341 go onu.ProcessOnuMessages(o.enableContext, stream, nil)
342 if onu.InternalState.Current() != "initialized" {
343 continue
344 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100345 if err := onu.InternalState.Event("discover"); err != nil {
346 log.Errorf("Error discover ONU: %v", err)
347 return err
Matteo Scandolo4747d292019-08-05 11:50:18 -0700348 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700349 }
350 }
351
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800352 oltLogger.Debug("Enable OLT Done")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700353 wg.Wait()
354 return nil
355}
356
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800357func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400358 ch := omcisim.GetChannel()
359
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100360 oltLogger.Debug("Starting OMCI Indication Channel")
William Kurkian9dadc5b2019-10-22 13:51:57 -0400361
David Bainbridge103cf022019-12-16 20:11:35 +0000362loop:
363 for {
364 select {
365 case <-ctx.Done():
366 oltLogger.Debug("OMCI processing canceled via context")
367 break loop
368 case message, ok := <-ch:
369 if !ok || ctx.Err() != nil {
370 oltLogger.Debug("OMCI processing canceled via channel close")
371 break loop
372 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800373
374 oltLogger.WithFields(log.Fields{
375 "messageType": message.Type,
376 "OnuId": message.Data.OnuId,
377 "IntfId": message.Data.IntfId,
378 }).Info("Received message on OMCI Sim channel")
379
David Bainbridge103cf022019-12-16 20:11:35 +0000380 onuId := message.Data.OnuId
381 intfId := message.Data.IntfId
382 onu, err := o.FindOnuById(intfId, onuId)
383 if err != nil {
384 oltLogger.Errorf("Failed to find onu: %v", err)
385 continue
386 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800387 go onu.processOmciMessage(message, stream)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400388 }
William Kurkian9dadc5b2019-10-22 13:51:57 -0400389 }
David Bainbridge103cf022019-12-16 20:11:35 +0000390
391 wg.Done()
William Kurkian9dadc5b2019-10-22 13:51:57 -0400392}
393
Matteo Scandolo4747d292019-08-05 11:50:18 -0700394// Helpers method
395
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700396func (o OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700397 for _, pon := range o.Pons {
398 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700399 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700400 }
401 }
402 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
403}
404
405func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
406 for _, nni := range o.Nnis {
407 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700408 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700409 }
410 }
411 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
412}
413
Scott Baker41724b82020-01-21 19:54:53 -0800414func (o *OltDevice) sendAlarmIndication(alarmInd *openolt.AlarmIndication, stream openolt.Openolt_EnableIndicationServer) {
415 data := &openolt.Indication_AlarmInd{AlarmInd: alarmInd}
416 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
417 oltLogger.Errorf("Failed to send Alarm Indication: %v", err)
418 return
419 }
420
421 oltLogger.WithFields(log.Fields{
422 "AlarmIndication": alarmInd,
423 }).Debug("Sent Indication_AlarmInd")
424}
425
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100426func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700427 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
428 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700429 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800430 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700431 }
432
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700433 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700434 "OperState": msg.OperState,
435 }).Debug("Sent Indication_OltInd")
436}
437
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100438func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700439 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800440 if msg.OperState == UP {
441 if err := nni.OperState.Event("enable"); err != nil {
442 log.WithFields(log.Fields{
443 "Type": nni.Type,
444 "IntfId": nni.ID,
445 "OperState": nni.OperState.Current(),
446 }).Errorf("Can't move NNI Port to enabled state: %v", err)
447 }
448 } else if msg.OperState == DOWN {
449 if err := nni.OperState.Event("disable"); err != nil {
450 log.WithFields(log.Fields{
451 "Type": nni.Type,
452 "IntfId": nni.ID,
453 "OperState": nni.OperState.Current(),
454 }).Errorf("Can't move NNI Port to disable state: %v", err)
455 }
456 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700457 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700458 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700459 Type: nni.Type,
460 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700461 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700462 }}
463
464 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700465 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800466 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700467 }
468
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700469 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700470 "Type": nni.Type,
471 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700472 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700473 }).Debug("Sent Indication_IntfOperInd for NNI")
474}
475
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100476func (o *OltDevice) sendPonIndication(msg PonIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700477 pon, _ := o.GetPonById(msg.PonPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800478 if msg.OperState == UP {
479 if err := pon.OperState.Event("enable"); err != nil {
480 log.WithFields(log.Fields{
481 "Type": pon.Type,
482 "IntfId": pon.ID,
483 "OperState": pon.OperState.Current(),
484 }).Errorf("Can't move PON Port to enable state: %v", err)
485 }
486 } else if msg.OperState == DOWN {
487 if err := pon.OperState.Event("disable"); err != nil {
488 log.WithFields(log.Fields{
489 "Type": pon.Type,
490 "IntfId": pon.ID,
491 "OperState": pon.OperState.Current(),
492 }).Errorf("Can't move PON Port to disable state: %v", err)
493 }
494 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700495 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700496 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700497 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700498 }}
499
500 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700501 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800502 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700503 }
504
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700505 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700506 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700507 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700508 }).Debug("Sent Indication_IntfInd")
509
510 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700511 Type: pon.Type,
512 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700513 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700514 }}
515
516 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700517 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800518 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700519 }
520
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700521 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700522 "Type": pon.Type,
523 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700524 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700525 }).Debug("Sent Indication_IntfOperInd for PON")
526}
527
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100528// processOltMessages handles messages received over the OpenOLT interface
David Bainbridge103cf022019-12-16 20:11:35 +0000529func (o *OltDevice) processOltMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100530 oltLogger.Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000531 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700532
David Bainbridge103cf022019-12-16 20:11:35 +0000533loop:
534 for {
535 select {
536 case <-ctx.Done():
537 oltLogger.Debug("OLT Indication processing canceled via context")
538 break loop
539 case message, ok := <-ch:
540 if !ok || ctx.Err() != nil {
541 oltLogger.Debug("OLT Indication processing canceled via closed channel")
542 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700543 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700544
David Bainbridge103cf022019-12-16 20:11:35 +0000545 oltLogger.WithFields(log.Fields{
546 "oltId": o.ID,
547 "messageType": message.Type,
548 }).Trace("Received message")
549
550 switch message.Type {
551 case OltIndication:
552 msg, _ := message.Data.(OltIndicationMessage)
553 if msg.OperState == UP {
554 o.InternalState.Event("enable")
555 o.OperState.Event("enable")
556 } else if msg.OperState == DOWN {
557 o.InternalState.Event("disable")
558 o.OperState.Event("disable")
559 }
560 o.sendOltIndication(msg, stream)
Scott Baker41724b82020-01-21 19:54:53 -0800561 case AlarmIndication:
562 alarmInd, _ := message.Data.(*openolt.AlarmIndication)
563 o.sendAlarmIndication(alarmInd, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000564 case NniIndication:
565 msg, _ := message.Data.(NniIndicationMessage)
566 o.sendNniIndication(msg, stream)
567 case PonIndication:
568 msg, _ := message.Data.(PonIndicationMessage)
569 o.sendPonIndication(msg, stream)
570 default:
571 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
572 }
573 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700574 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100575 wg.Done()
576 oltLogger.Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700577}
578
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100579// processNniPacketIns handles messages received over the NNI interface
David Bainbridge103cf022019-12-16 20:11:35 +0000580func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700581 oltLogger.WithFields(log.Fields{
582 "nniChannel": o.nniPktInChannel,
Matteo Scandolo401503a2019-12-11 14:48:14 -0800583 }).Debug("Started Processing Packets arriving from the NNI")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700584 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700585
David Bainbridge103cf022019-12-16 20:11:35 +0000586 ch := o.nniPktInChannel
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700587
David Bainbridge103cf022019-12-16 20:11:35 +0000588loop:
589 for {
590 select {
591 case <-ctx.Done():
592 oltLogger.Debug("NNI Indication processing canceled via context")
593 break loop
594 case message, ok := <-ch:
595 if !ok || ctx.Err() != nil {
596 oltLogger.Debug("NNI Indication processing canceled via channel closed")
597 break loop
598 }
599 oltLogger.Tracef("Received packets on NNI Channel")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700600
David Bainbridge103cf022019-12-16 20:11:35 +0000601 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700602
David Bainbridge103cf022019-12-16 20:11:35 +0000603 if err != nil {
604 log.WithFields(log.Fields{
605 "IntfType": "nni",
606 "IntfId": nniId,
607 "Pkt": message.Pkt.Data(),
608 }).Error("Can't find Dst MacAddress in packet")
609 return
610 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700611
David Bainbridge103cf022019-12-16 20:11:35 +0000612 onu, err := o.FindOnuByMacAddress(onuMac)
613 if err != nil {
614 log.WithFields(log.Fields{
615 "IntfType": "nni",
616 "IntfId": nniId,
617 "Pkt": message.Pkt.Data(),
618 "MacAddress": onuMac.String(),
619 }).Error("Can't find ONU with MacAddress")
620 return
621 }
622
623 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
624 if err != nil {
625 log.Error("Fail to add double tag to packet")
626 }
627
628 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
629 IntfType: "nni",
630 IntfId: nniId,
631 Pkt: doubleTaggedPkt.Data()}}
632 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
633 oltLogger.WithFields(log.Fields{
634 "IntfType": data.PktInd.IntfType,
635 "IntfId": nniId,
636 "Pkt": doubleTaggedPkt.Data(),
637 }).Errorf("Fail to send PktInd indication: %v", err)
638 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700639 oltLogger.WithFields(log.Fields{
640 "IntfType": data.PktInd.IntfType,
641 "IntfId": nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700642 "Pkt": doubleTaggedPkt.Data(),
David Bainbridge103cf022019-12-16 20:11:35 +0000643 "OnuSn": onu.Sn(),
644 }).Tracef("Sent PktInd indication")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700645 }
646 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100647 wg.Done()
648 oltLogger.WithFields(log.Fields{
649 "nniChannel": o.nniPktInChannel,
650 }).Warn("Stopped handling NNI Channel")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700651}
652
Pragya Arya6a708d62020-01-01 17:17:20 +0530653func (o *OltDevice) handleReenableOlt() {
654 // enable OLT
655 oltMsg := Message{
656 Type: OltIndication,
657 Data: OltIndicationMessage{
658 OperState: UP,
659 },
660 }
661 o.channel <- oltMsg
662
663 for i := range olt.Pons {
664 for _, onu := range olt.Pons[i].Onus {
665 if err := onu.InternalState.Event("discover"); err != nil {
666 log.Errorf("Error discover ONU: %v", err)
667 }
668 }
669 }
670
671}
672
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700673// returns an ONU with a given Serial Number
674func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200675 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700676 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700677 for _, pon := range o.Pons {
678 for _, onu := range pon.Onus {
679 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700680 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700681 }
682 }
683 }
684
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700685 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-serial-number-%s", serialNumber))
686}
687
William Kurkian9dadc5b2019-10-22 13:51:57 -0400688// returns an ONU with a given interface/Onu Id
689func (o OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200690 // TODO this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400691 // memoizing it will remove the bottleneck
692 for _, pon := range o.Pons {
693 if pon.ID == intfId {
694 for _, onu := range pon.Onus {
695 if onu.ID == onuId {
696 return onu, nil
697 }
698 }
699 }
700 }
701 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-id-%v-%v", intfId, onuId))
702}
703
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700704// returns an ONU with a given Mac Address
705func (o OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200706 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700707 // memoizing it will remove the bottleneck
708 for _, pon := range o.Pons {
709 for _, onu := range pon.Onus {
710 if onu.HwAddress.String() == mac.String() {
Matteo Scandolo27428702019-10-11 16:21:16 -0700711 return onu, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700712 }
713 }
714 }
715
716 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-mac-address-%s", mac))
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700717}
718
Matteo Scandolo4747d292019-08-05 11:50:18 -0700719// GRPC Endpoints
720
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700721func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700722 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700723 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700724 }).Info("Received ActivateOnu call from VOLTHA")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700725
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700726 pon, _ := o.GetPonById(onu.IntfId)
727 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
William Kurkian0418bc82019-11-06 12:16:24 -0500728 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700729
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700730 if err := _onu.OperState.Event("enable"); err != nil {
731 oltLogger.WithFields(log.Fields{
732 "IntfId": _onu.PonPortID,
733 "OnuSn": _onu.Sn(),
734 "OnuId": _onu.ID,
735 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700736 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700737 if err := _onu.InternalState.Event("enable"); err != nil {
738 oltLogger.WithFields(log.Fields{
739 "IntfId": _onu.PonPortID,
740 "OnuSn": _onu.Sn(),
741 "OnuId": _onu.ID,
742 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
743 }
744
745 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
746
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700747 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700748}
749
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700750func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700751 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700752 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700753}
754
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700755func (o OltDevice) DeleteOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700756 oltLogger.Error("DeleteOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700757 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700758}
759
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700760func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700761 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800762 oltLogger.WithFields(log.Fields{
763 "oltId": o.ID,
764 }).Info("Disabling OLT")
765
Matteo Scandolo401503a2019-12-11 14:48:14 -0800766 for _, pon := range o.Pons {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800767 // disable PONs
768 msg := Message{
769 Type: PonIndication,
770 Data: PonIndicationMessage{
771 OperState: DOWN,
772 PonPortID: pon.ID,
773 },
774 }
775
776 o.channel <- msg
777 }
778
Matteo Scandolo401503a2019-12-11 14:48:14 -0800779 // Note that we are not disabling the NNI as the real OLT does not.
780 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800781
782 // disable OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100783 oltMsg := Message{
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700784 Type: OltIndication,
785 Data: OltIndicationMessage{
786 OperState: DOWN,
787 },
788 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100789 o.channel <- oltMsg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700790 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700791}
792
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700793func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700794 oltLogger.Error("DisablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700795 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700796}
797
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100798func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700799 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700800 o.Enable(stream)
801 return nil
802}
803
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700804func (o OltDevice) EnablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700805 oltLogger.Error("EnablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700806 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700807}
808
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700809func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700810 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700811 "IntfId": flow.AccessIntfId,
812 "OnuId": flow.OnuId,
813 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700814 "InnerVlan": flow.Classifier.IVid,
815 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700816 "FlowType": flow.FlowType,
817 "FlowId": flow.FlowId,
818 "UniID": flow.UniId,
819 "PortNo": flow.PortNo,
820 }).Tracef("OLT receives Flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700821 // TODO optionally store flows somewhere
822
823 if flow.AccessIntfId == -1 {
824 oltLogger.WithFields(log.Fields{
825 "FlowId": flow.FlowId,
826 }).Debugf("This is an OLT flow")
827 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700828 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700829 if err != nil {
830 oltLogger.WithFields(log.Fields{
831 "OnuId": flow.OnuId,
832 "IntfId": flow.AccessIntfId,
833 "err": err,
834 }).Error("Can't find PonPort")
835 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700836 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700837 if err != nil {
838 oltLogger.WithFields(log.Fields{
839 "OnuId": flow.OnuId,
840 "IntfId": flow.AccessIntfId,
841 "err": err,
842 }).Error("Can't find Onu")
843 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700844
845 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700846 Type: FlowUpdate,
847 Data: OnuFlowUpdateMessage{
848 PonPortID: pon.ID,
849 OnuID: onu.ID,
850 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700851 },
852 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700853 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700854 }
855
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700856 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700857}
858
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700859func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
860 oltLogger.Tracef("received FlowRemove")
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700861 // TODO store flows somewhere
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700862 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700863}
864
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700865func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo18859852020-01-15 13:33:57 -0800866 res := openolt.Heartbeat{HeartbeatSignature: uint32(time.Now().Unix())}
867 oltLogger.WithFields(log.Fields{
868 "signature": res.HeartbeatSignature,
869 }).Trace("HeartbeatCheck")
870 return &res, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700871}
872
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700873func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700874
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700875 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700876 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700877 "PonPorts": o.NumPon,
878 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700879 devinfo := new(openolt.DeviceInfo)
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100880 devinfo.Vendor = common.Options.Olt.Vendor
881 devinfo.Model = common.Options.Olt.Model
882 devinfo.HardwareVersion = common.Options.Olt.HardwareVersion
883 devinfo.FirmwareVersion = common.Options.Olt.FirmwareVersion
884 devinfo.Technology = common.Options.Olt.Technology
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700885 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700886 devinfo.OnuIdStart = 1
887 devinfo.OnuIdEnd = 255
888 devinfo.AllocIdStart = 1024
889 devinfo.AllocIdEnd = 16383
890 devinfo.GemportIdStart = 1024
891 devinfo.GemportIdEnd = 65535
892 devinfo.FlowIdStart = 1
893 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -0700894 devinfo.DeviceSerialNumber = o.SerialNumber
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100895 devinfo.DeviceId = common.Options.Olt.DeviceId
Matteo Scandolo4747d292019-08-05 11:50:18 -0700896
897 return devinfo, nil
898}
899
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700900func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700901 pon, _ := o.GetPonById(omci_msg.IntfId)
902 onu, _ := pon.GetOnuById(omci_msg.OnuId)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700903 oltLogger.WithFields(log.Fields{
904 "IntfId": onu.PonPortID,
905 "OnuId": onu.ID,
906 "OnuSn": onu.Sn(),
907 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700908 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700909 Type: OMCI,
910 Data: OmciMessage{
911 OnuSN: onu.SerialNumber,
912 OnuID: onu.ID,
913 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700914 },
915 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700916 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700917 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700918}
919
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700920func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700921 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700922 if err != nil {
923 oltLogger.WithFields(log.Fields{
924 "OnuId": onuPkt.OnuId,
925 "IntfId": onuPkt.IntfId,
926 "err": err,
927 }).Error("Can't find PonPort")
928 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700929 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700930 if err != nil {
931 oltLogger.WithFields(log.Fields{
932 "OnuId": onuPkt.OnuId,
933 "IntfId": onuPkt.IntfId,
934 "err": err,
935 }).Error("Can't find Onu")
936 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700937
Matteo Scandolo075b1892019-10-07 12:11:07 -0700938 oltLogger.WithFields(log.Fields{
939 "IntfId": onu.PonPortID,
940 "OnuId": onu.ID,
941 "OnuSn": onu.Sn(),
942 }).Tracef("Received OnuPacketOut")
943
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700944 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700945 pktType, err := packetHandlers.IsEapolOrDhcp(rawpkt)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700946
Matteo Scandolo075b1892019-10-07 12:11:07 -0700947 msg := Message{
948 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700949 Data: OnuPacketMessage{
Matteo Scandolo075b1892019-10-07 12:11:07 -0700950 IntfId: onuPkt.IntfId,
951 OnuId: onuPkt.OnuId,
952 Packet: rawpkt,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700953 Type: pktType,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700954 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700955 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700956 onu.Channel <- msg
957
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700958 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700959}
960
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700961func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800962 oltLogger.WithFields(log.Fields{
963 "oltId": o.ID,
964 }).Info("Shutting down")
965 go o.RestartOLT()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700966 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700967}
968
969func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Pragya Arya6a708d62020-01-01 17:17:20 +0530970 oltLogger.WithFields(log.Fields{
971 "oltId": o.ID,
972 }).Info("Received ReenableOlt request from VOLTHA")
973
974 for _, pon := range o.Pons {
975 msg := Message{
976 Type: PonIndication,
977 Data: PonIndicationMessage{
978 OperState: UP,
979 PonPortID: pon.ID,
980 },
981 }
982 o.channel <- msg
983 }
984
985 // Openolt adapter will start processing indications only after success reponse of ReenableOlt
986 // thats why need to send OLT and ONU indications after return of this function
987 go o.handleReenableOlt()
988
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700989 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700990}
991
992func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700993 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
994
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100995 o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700996 // NOTE should we return an error if sendNniPakcet fails?
997 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700998}
999
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001000func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001001 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001002 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001003}
1004
Matteo Scandolo4747d292019-08-05 11:50:18 -07001005func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001006 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001007 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001008}
1009
1010func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001011 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001012 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -07001013}
1014
1015func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001016 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001017 return new(openolt.Empty), nil
1018}
1019
1020func (s OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001021 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001022 return new(openolt.Empty), nil
1023}
1024
1025func (s OltDevice) CreateTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001026 oltLogger.Info("received CreateTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001027 return new(openolt.Empty), nil
1028}
1029
1030func (s OltDevice) RemoveTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001031 oltLogger.Info("received RemoveTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001032 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001033}
Scott Baker41724b82020-01-21 19:54:53 -08001034
1035// assumes caller has properly formulated an openolt.AlarmIndication
1036func (o OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
1037 msg := Message{
1038 Type: AlarmIndication,
1039 Data: ind,
1040 }
1041
1042 o.channel <- msg
1043 return nil
1044}