blob: f68ee9eaa11f80ba19b426b4e20516e433e05b64 [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
Pragya Arya1881df02020-01-29 18:05:01 +053050 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 Delay int
60 ControlledActivation mode
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
Pragya Arya1881df02020-01-29 18:05:01 +053081func CreateOLT(oltId int, nni int, pon int, onuPerPon int, sTag int, cTagInit int, auth bool, dhcp bool, delay int, ca string, 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
Pragya Arya1881df02020-01-29 18:05:01 +0530103 if val, ok := ControlledActivationModes[ca]; ok {
104 olt.ControlledActivation = val
105 } else {
106 oltLogger.Warn("Unknown ControlledActivation Mode given, running in Default mode")
107 olt.ControlledActivation = Default
108 }
109
Matteo Scandolo4747d292019-08-05 11:50:18 -0700110 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700111 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700112 olt.InternalState = fsm.NewFSM(
113 "created",
114 fsm.Events{
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800115 {Name: "initialize", Src: []string{"created", "deleted"}, Dst: "initialized"},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100116 {Name: "enable", Src: []string{"initialized", "disabled"}, Dst: "enabled"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700117 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
Mahir Gunyel6dad4452020-01-06 12:59:04 -0800118 //delete event in enabled state below is for reboot OLT case.
119 {Name: "delete", Src: []string{"disabled", "enabled"}, Dst: "deleted"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700120 },
121 fsm.Callbacks{
122 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700123 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700124 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100125 "enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
Matteo Scandolo4747d292019-08-05 11:50:18 -0700126 },
127 )
128
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700129 if isMock != true {
130 // create NNI Port
131 nniPort, err := CreateNNI(&olt)
132 if err != nil {
133 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
134 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700135
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700136 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700137 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700138
Matteo Scandolo4747d292019-08-05 11:50:18 -0700139 // create PON ports
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700140 availableCTag := cTagInit
Matteo Scandolo4747d292019-08-05 11:50:18 -0700141 for i := 0; i < pon; i++ {
Pragya Arya1881df02020-01-29 18:05:01 +0530142 p := CreatePonPort(&olt, uint32(i))
Matteo Scandolo4747d292019-08-05 11:50:18 -0700143
144 // create ONU devices
145 for j := 0; j < onuPerPon; j++ {
Pragya Arya1cbefa42020-01-13 12:15:29 +0530146 o := CreateONU(&olt, *p, uint32(j+1), sTag, availableCTag, auth, dhcp, isMock)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700147 p.Onus = append(p.Onus, o)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700148 availableCTag = availableCTag + 1
Matteo Scandolo4747d292019-08-05 11:50:18 -0700149 }
150
Pragya Arya6a708d62020-01-01 17:17:20 +0530151 olt.Pons = append(olt.Pons, p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700152 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100153
Matteo Scandolod32c3822019-11-26 15:57:46 -0700154 if isMock != true {
155 if err := olt.InternalState.Event("initialize"); err != nil {
156 log.Errorf("Error initializing OLT: %v", err)
157 return nil
158 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100159 }
160
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700161 return &olt
162}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700163
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100164func (o *OltDevice) InitOlt() error {
165
166 if oltServer == nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800167 oltServer, _ = o.newOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100168 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800169 // FIXME there should never be a server running if we are initializing the OLT
170 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100171 }
172
173 // create new channel for processOltMessages Go routine
174 o.channel = make(chan Message)
175
176 o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
177 // FIXME we are assuming we have only one NNI
178 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800179 // NOTE we want to make sure the state is down when we initialize the OLT,
180 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
181 // in-band management
182 o.Nnis[0].OperState.SetState("down")
183 ch, handle, err := o.Nnis[0].NewVethChan()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100184 if err == nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800185 oltLogger.WithFields(log.Fields{
186 "Type": o.Nnis[0].Type,
187 "IntfId": o.Nnis[0].ID,
188 "OperState": o.Nnis[0].OperState.Current(),
189 }).Info("NNI Channel created")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100190 o.nniPktInChannel = ch
Matteo Scandolo401503a2019-12-11 14:48:14 -0800191 o.nniHandle = handle
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100192 } else {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800193 oltLogger.Errorf("Error getting NNI channel: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100194 }
195 }
196
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100197 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 {
Pragya Arya1881df02020-01-29 18:05:01 +0530219 oltLogger.Errorf("Error in stopping OLT server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100220 return err
221 }
222
Pragya Arya1881df02020-01-29 18:05:01 +0530223 for _, pon := range olt.Pons {
224 msg := Message{
225 Type: PonIndication,
226 Data: PonIndicationMessage{
227 OperState: DOWN,
228 PonPortID: pon.ID,
229 },
230 }
231 o.channel <- msg
232
233 for _, onu := range pon.Onus {
234 if onu.InternalState.Current() != "initialized" {
235 onu.InternalState.Event("disable")
236 }
237 }
238 }
239
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100240 // terminate the OLT's processOltMessages go routine
241 close(o.channel)
242 // terminate the OLT's processNniPacketIns go routine
Andy Bavier421f4d52020-01-21 15:39:22 -0700243 go o.nniHandle.Close()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100244 close(o.nniPktInChannel)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100245
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100246 time.Sleep(time.Duration(rebootDelay) * time.Second)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100247
248 if err := o.InternalState.Event("initialize"); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800249 oltLogger.WithFields(log.Fields{
250 "oltId": o.ID,
251 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100252 return err
253 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800254 oltLogger.WithFields(log.Fields{
255 "oltId": o.ID,
256 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100257 return nil
258}
259
260// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800261func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100262 address := common.Options.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700263 lis, err := net.Listen("tcp", address)
264 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700265 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700266 }
267 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100268
Matteo Scandolo4747d292019-08-05 11:50:18 -0700269 openolt.RegisterOpenoltServer(grpcServer, o)
270
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100271 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700272
Matteo Scandolo4747d292019-08-05 11:50:18 -0700273 go grpcServer.Serve(lis)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100274 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700275
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100276 return grpcServer, nil
277}
278
279// StopOltServer stops the OpenOLT grpc server
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800280func (o *OltDevice) StopOltServer() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100281 // TODO handle poweroff vs graceful shutdown
282 if oltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800283 oltLogger.WithFields(log.Fields{
284 "oltId": o.SerialNumber,
285 }).Warnf("Stopping OLT gRPC server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100286 oltServer.Stop()
287 oltServer = nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700288 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800289
Matteo Scandolo4747d292019-08-05 11:50:18 -0700290 return nil
291}
292
293// Device Methods
294
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100295// Enable implements the OpenOLT EnableIndicationServer functionality
296func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700297 oltLogger.Debug("Enable OLT called")
Pragya Arya1881df02020-01-29 18:05:01 +0530298 rebootFlag := false
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700299
David Bainbridge103cf022019-12-16 20:11:35 +0000300 // If enabled has already been called then an enabled context has
301 // been created. If this is the case then we want to cancel all the
302 // proessing loops associated with that enable before we recreate
303 // new ones
304 o.Lock()
305 if o.enableContext != nil && o.enableContextCancel != nil {
306 o.enableContextCancel()
Pragya Arya1881df02020-01-29 18:05:01 +0530307 rebootFlag = true
David Bainbridge103cf022019-12-16 20:11:35 +0000308 }
309 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
310 o.Unlock()
311
Matteo Scandolo4747d292019-08-05 11:50:18 -0700312 wg := sync.WaitGroup{}
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800313 wg.Add(3)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700314
Pragya Arya1cbefa42020-01-13 12:15:29 +0530315 o.OpenoltStream = &stream
316
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100317 // create Go routine to process all OLT events
David Bainbridge103cf022019-12-16 20:11:35 +0000318 go o.processOltMessages(o.enableContext, stream, &wg)
319 go o.processNniPacketIns(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700320
321 // enable the OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100322 oltMsg := Message{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700323 Type: OltIndication,
324 Data: OltIndicationMessage{
325 OperState: UP,
326 },
327 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100328 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700329
330 // send NNI Port Indications
331 for _, nni := range o.Nnis {
332 msg := Message{
333 Type: NniIndication,
334 Data: NniIndicationMessage{
335 OperState: UP,
336 NniPortID: nni.ID,
337 },
338 }
339 o.channel <- msg
340 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100341
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800342 go o.processOmciMessages(o.enableContext, stream, &wg)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100343
Pragya Arya1881df02020-01-29 18:05:01 +0530344 if rebootFlag == true {
345 for _, pon := range o.Pons {
346 if pon.InternalState.Current() == "disabled" {
347 msg := Message{
348 Type: PonIndication,
349 Data: PonIndicationMessage{
350 OperState: UP,
351 PonPortID: pon.ID,
352 },
353 }
354 o.channel <- msg
David Bainbridge103cf022019-12-16 20:11:35 +0000355 }
Pragya Arya1881df02020-01-29 18:05:01 +0530356 }
357 } else {
358
359 // 1. controlledActivation == Default: Send both PON and ONUs indications
360 // 2. controlledActivation == only-onu: that means only ONUs will be controlled activated, so auto send PON indications
361
362 if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
363 // send PON Port indications
364 for _, pon := range o.Pons {
365 msg := Message{
366 Type: PonIndication,
367 Data: PonIndicationMessage{
368 OperState: UP,
369 PonPortID: pon.ID,
370 },
371 }
372 o.channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700373 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700374 }
375 }
376
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800377 oltLogger.Debug("Enable OLT Done")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700378 wg.Wait()
379 return nil
380}
381
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800382func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400383 ch := omcisim.GetChannel()
384
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100385 oltLogger.Debug("Starting OMCI Indication Channel")
William Kurkian9dadc5b2019-10-22 13:51:57 -0400386
David Bainbridge103cf022019-12-16 20:11:35 +0000387loop:
388 for {
389 select {
390 case <-ctx.Done():
391 oltLogger.Debug("OMCI processing canceled via context")
392 break loop
393 case message, ok := <-ch:
394 if !ok || ctx.Err() != nil {
395 oltLogger.Debug("OMCI processing canceled via channel close")
396 break loop
397 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800398
399 oltLogger.WithFields(log.Fields{
400 "messageType": message.Type,
401 "OnuId": message.Data.OnuId,
402 "IntfId": message.Data.IntfId,
403 }).Info("Received message on OMCI Sim channel")
404
David Bainbridge103cf022019-12-16 20:11:35 +0000405 onuId := message.Data.OnuId
406 intfId := message.Data.IntfId
407 onu, err := o.FindOnuById(intfId, onuId)
408 if err != nil {
409 oltLogger.Errorf("Failed to find onu: %v", err)
410 continue
411 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800412 go onu.processOmciMessage(message, stream)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400413 }
William Kurkian9dadc5b2019-10-22 13:51:57 -0400414 }
David Bainbridge103cf022019-12-16 20:11:35 +0000415
416 wg.Done()
William Kurkian9dadc5b2019-10-22 13:51:57 -0400417}
418
Matteo Scandolo4747d292019-08-05 11:50:18 -0700419// Helpers method
420
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700421func (o OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700422 for _, pon := range o.Pons {
423 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700424 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700425 }
426 }
427 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
428}
429
430func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
431 for _, nni := range o.Nnis {
432 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700433 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700434 }
435 }
436 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
437}
438
Scott Baker41724b82020-01-21 19:54:53 -0800439func (o *OltDevice) sendAlarmIndication(alarmInd *openolt.AlarmIndication, stream openolt.Openolt_EnableIndicationServer) {
440 data := &openolt.Indication_AlarmInd{AlarmInd: alarmInd}
441 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
442 oltLogger.Errorf("Failed to send Alarm Indication: %v", err)
443 return
444 }
445
446 oltLogger.WithFields(log.Fields{
447 "AlarmIndication": alarmInd,
448 }).Debug("Sent Indication_AlarmInd")
449}
450
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100451func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700452 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
453 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700454 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800455 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700456 }
457
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700458 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700459 "OperState": msg.OperState,
460 }).Debug("Sent Indication_OltInd")
461}
462
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100463func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700464 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800465 if msg.OperState == UP {
466 if err := nni.OperState.Event("enable"); err != nil {
467 log.WithFields(log.Fields{
468 "Type": nni.Type,
469 "IntfId": nni.ID,
470 "OperState": nni.OperState.Current(),
471 }).Errorf("Can't move NNI Port to enabled state: %v", err)
472 }
473 } else if msg.OperState == DOWN {
474 if err := nni.OperState.Event("disable"); err != nil {
475 log.WithFields(log.Fields{
476 "Type": nni.Type,
477 "IntfId": nni.ID,
478 "OperState": nni.OperState.Current(),
479 }).Errorf("Can't move NNI Port to disable state: %v", err)
480 }
481 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700482 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700483 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700484 Type: nni.Type,
485 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700486 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700487 }}
488
489 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700490 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800491 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700492 }
493
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700494 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700495 "Type": nni.Type,
496 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700497 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700498 }).Debug("Sent Indication_IntfOperInd for NNI")
499}
500
Pragya Arya1881df02020-01-29 18:05:01 +0530501func (o *OltDevice) sendPonIndication(ponPortID uint32) {
502
503 stream := *o.OpenoltStream
504 pon, _ := o.GetPonById(ponPortID)
505 // Send IntfIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700506 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700507 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: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700512 oltLogger.Errorf("Failed to send Indication_IntfInd: %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 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700518 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700519 }).Debug("Sent Indication_IntfInd")
520
Pragya Arya1881df02020-01-29 18:05:01 +0530521 // Send IntfOperIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700522 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700523 Type: pon.Type,
524 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700525 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700526 }}
527
528 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700529 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800530 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700531 }
532
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700533 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700534 "Type": pon.Type,
535 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700536 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700537 }).Debug("Sent Indication_IntfOperInd for PON")
538}
539
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100540// processOltMessages handles messages received over the OpenOLT interface
David Bainbridge103cf022019-12-16 20:11:35 +0000541func (o *OltDevice) processOltMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100542 oltLogger.Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000543 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700544
David Bainbridge103cf022019-12-16 20:11:35 +0000545loop:
546 for {
547 select {
548 case <-ctx.Done():
549 oltLogger.Debug("OLT Indication processing canceled via context")
550 break loop
551 case message, ok := <-ch:
552 if !ok || ctx.Err() != nil {
553 oltLogger.Debug("OLT Indication processing canceled via closed channel")
554 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700555 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700556
David Bainbridge103cf022019-12-16 20:11:35 +0000557 oltLogger.WithFields(log.Fields{
558 "oltId": o.ID,
559 "messageType": message.Type,
560 }).Trace("Received message")
561
562 switch message.Type {
563 case OltIndication:
564 msg, _ := message.Data.(OltIndicationMessage)
565 if msg.OperState == UP {
566 o.InternalState.Event("enable")
567 o.OperState.Event("enable")
568 } else if msg.OperState == DOWN {
569 o.InternalState.Event("disable")
570 o.OperState.Event("disable")
571 }
572 o.sendOltIndication(msg, stream)
Scott Baker41724b82020-01-21 19:54:53 -0800573 case AlarmIndication:
574 alarmInd, _ := message.Data.(*openolt.AlarmIndication)
575 o.sendAlarmIndication(alarmInd, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000576 case NniIndication:
577 msg, _ := message.Data.(NniIndicationMessage)
578 o.sendNniIndication(msg, stream)
579 case PonIndication:
580 msg, _ := message.Data.(PonIndicationMessage)
Pragya Arya1881df02020-01-29 18:05:01 +0530581 pon, _ := o.GetPonById(msg.PonPortID)
582 if msg.OperState == UP {
583 pon.OperState.Event("enable")
584 pon.InternalState.Event("enable")
585 } else if msg.OperState == DOWN {
586 pon.OperState.Event("disable")
587 pon.InternalState.Event("disable")
588 }
David Bainbridge103cf022019-12-16 20:11:35 +0000589 default:
590 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
591 }
592 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700593 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100594 wg.Done()
595 oltLogger.Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700596}
597
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100598// processNniPacketIns handles messages received over the NNI interface
David Bainbridge103cf022019-12-16 20:11:35 +0000599func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700600 oltLogger.WithFields(log.Fields{
601 "nniChannel": o.nniPktInChannel,
Matteo Scandolo401503a2019-12-11 14:48:14 -0800602 }).Debug("Started Processing Packets arriving from the NNI")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700603 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700604
David Bainbridge103cf022019-12-16 20:11:35 +0000605 ch := o.nniPktInChannel
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700606
David Bainbridge103cf022019-12-16 20:11:35 +0000607loop:
608 for {
609 select {
610 case <-ctx.Done():
611 oltLogger.Debug("NNI Indication processing canceled via context")
612 break loop
613 case message, ok := <-ch:
614 if !ok || ctx.Err() != nil {
615 oltLogger.Debug("NNI Indication processing canceled via channel closed")
616 break loop
617 }
618 oltLogger.Tracef("Received packets on NNI Channel")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700619
David Bainbridge103cf022019-12-16 20:11:35 +0000620 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700621
David Bainbridge103cf022019-12-16 20:11:35 +0000622 if err != nil {
623 log.WithFields(log.Fields{
624 "IntfType": "nni",
625 "IntfId": nniId,
626 "Pkt": message.Pkt.Data(),
627 }).Error("Can't find Dst MacAddress in packet")
628 return
629 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700630
David Bainbridge103cf022019-12-16 20:11:35 +0000631 onu, err := o.FindOnuByMacAddress(onuMac)
632 if err != nil {
633 log.WithFields(log.Fields{
634 "IntfType": "nni",
635 "IntfId": nniId,
636 "Pkt": message.Pkt.Data(),
637 "MacAddress": onuMac.String(),
638 }).Error("Can't find ONU with MacAddress")
639 return
640 }
641
642 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
643 if err != nil {
644 log.Error("Fail to add double tag to packet")
645 }
646
647 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
648 IntfType: "nni",
649 IntfId: nniId,
650 Pkt: doubleTaggedPkt.Data()}}
651 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
652 oltLogger.WithFields(log.Fields{
653 "IntfType": data.PktInd.IntfType,
654 "IntfId": nniId,
655 "Pkt": doubleTaggedPkt.Data(),
656 }).Errorf("Fail to send PktInd indication: %v", err)
657 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700658 oltLogger.WithFields(log.Fields{
659 "IntfType": data.PktInd.IntfType,
660 "IntfId": nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700661 "Pkt": doubleTaggedPkt.Data(),
David Bainbridge103cf022019-12-16 20:11:35 +0000662 "OnuSn": onu.Sn(),
663 }).Tracef("Sent PktInd indication")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700664 }
665 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100666 wg.Done()
667 oltLogger.WithFields(log.Fields{
668 "nniChannel": o.nniPktInChannel,
669 }).Warn("Stopped handling NNI Channel")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700670}
671
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700672// returns an ONU with a given Serial Number
673func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200674 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700675 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700676 for _, pon := range o.Pons {
677 for _, onu := range pon.Onus {
678 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700679 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700680 }
681 }
682 }
683
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700684 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-serial-number-%s", serialNumber))
685}
686
William Kurkian9dadc5b2019-10-22 13:51:57 -0400687// returns an ONU with a given interface/Onu Id
688func (o OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200689 // TODO this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400690 // memoizing it will remove the bottleneck
691 for _, pon := range o.Pons {
692 if pon.ID == intfId {
693 for _, onu := range pon.Onus {
694 if onu.ID == onuId {
695 return onu, nil
696 }
697 }
698 }
699 }
700 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-id-%v-%v", intfId, onuId))
701}
702
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700703// returns an ONU with a given Mac Address
704func (o OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200705 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700706 // memoizing it will remove the bottleneck
707 for _, pon := range o.Pons {
708 for _, onu := range pon.Onus {
709 if onu.HwAddress.String() == mac.String() {
Matteo Scandolo27428702019-10-11 16:21:16 -0700710 return onu, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700711 }
712 }
713 }
714
715 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-mac-address-%s", mac))
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700716}
717
Matteo Scandolo4747d292019-08-05 11:50:18 -0700718// GRPC Endpoints
719
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700720func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700721 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700722 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700723 }).Info("Received ActivateOnu call from VOLTHA")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700724
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700725 pon, _ := o.GetPonById(onu.IntfId)
726 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
William Kurkian0418bc82019-11-06 12:16:24 -0500727 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700728
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700729 if err := _onu.OperState.Event("enable"); err != nil {
730 oltLogger.WithFields(log.Fields{
731 "IntfId": _onu.PonPortID,
732 "OnuSn": _onu.Sn(),
733 "OnuId": _onu.ID,
734 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700735 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700736 if err := _onu.InternalState.Event("enable"); err != nil {
737 oltLogger.WithFields(log.Fields{
738 "IntfId": _onu.PonPortID,
739 "OnuSn": _onu.Sn(),
740 "OnuId": _onu.ID,
741 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
742 }
743
744 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
745
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700746 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700747}
748
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700749func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700750 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700751 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700752}
753
Pragya Arya1cbefa42020-01-13 12:15:29 +0530754func (o OltDevice) DeleteOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
755 oltLogger.WithFields(log.Fields{
756 "IntfId": onu.IntfId,
757 "OnuId": onu.OnuId,
758 }).Info("Received DeleteOnu call from VOLTHA")
759
760 pon, err := o.GetPonById(onu.IntfId)
761 if err != nil {
762 oltLogger.WithFields(log.Fields{
763 "OnuId": onu.OnuId,
764 "IntfId": onu.IntfId,
765 "err": err,
766 }).Error("Can't find PonPort")
767 }
768 _onu, err := pon.GetOnuById(onu.OnuId)
769 if err != nil {
770 oltLogger.WithFields(log.Fields{
771 "OnuId": onu.OnuId,
772 "IntfId": onu.IntfId,
773 "err": err,
774 }).Error("Can't find Onu")
775 }
776
777 if err := _onu.InternalState.Event("initialize"); err != nil {
778 oltLogger.WithFields(log.Fields{
779 "IntfId": _onu.PonPortID,
780 "OnuSn": _onu.Sn(),
781 "OnuId": _onu.ID,
782 }).Infof("Failed to transition ONU to initialized state: %s", err.Error())
783 }
784
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700785 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700786}
787
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700788func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700789 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800790 oltLogger.WithFields(log.Fields{
791 "oltId": o.ID,
792 }).Info("Disabling OLT")
793
Matteo Scandolo401503a2019-12-11 14:48:14 -0800794 for _, pon := range o.Pons {
Pragya Arya1881df02020-01-29 18:05:01 +0530795 if pon.InternalState.Current() == "enabled" {
796 // disable PONs
797 msg := Message{
798 Type: PonIndication,
799 Data: PonIndicationMessage{
800 OperState: DOWN,
801 PonPortID: pon.ID,
802 },
803 }
804 o.channel <- msg
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800805 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800806 }
807
Matteo Scandolo401503a2019-12-11 14:48:14 -0800808 // Note that we are not disabling the NNI as the real OLT does not.
809 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800810
811 // disable OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100812 oltMsg := Message{
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700813 Type: OltIndication,
814 Data: OltIndicationMessage{
815 OperState: DOWN,
816 },
817 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100818 o.channel <- oltMsg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700819 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700820}
821
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700822func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700823 oltLogger.Error("DisablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700824 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700825}
826
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100827func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700828 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700829 o.Enable(stream)
830 return nil
831}
832
Pragya Arya1881df02020-01-29 18:05:01 +0530833func (o OltDevice) EnablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
834 oltLogger.Errorf("EnablePonIf request received for PON %d", intf.IntfId)
835 ponID := intf.GetIntfId()
836 msg := Message{
837 Type: PonIndication,
838 Data: PonIndicationMessage{
839 OperState: UP,
840 PonPortID: ponID,
841 },
842 }
843 o.channel <- msg
844
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700845 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700846}
847
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700848func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700849 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700850 "IntfId": flow.AccessIntfId,
851 "OnuId": flow.OnuId,
852 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700853 "InnerVlan": flow.Classifier.IVid,
854 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700855 "FlowType": flow.FlowType,
856 "FlowId": flow.FlowId,
857 "UniID": flow.UniId,
858 "PortNo": flow.PortNo,
859 }).Tracef("OLT receives Flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700860 // TODO optionally store flows somewhere
861
862 if flow.AccessIntfId == -1 {
863 oltLogger.WithFields(log.Fields{
864 "FlowId": flow.FlowId,
865 }).Debugf("This is an OLT flow")
866 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700867 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700868 if err != nil {
869 oltLogger.WithFields(log.Fields{
870 "OnuId": flow.OnuId,
871 "IntfId": flow.AccessIntfId,
872 "err": err,
873 }).Error("Can't find PonPort")
874 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700875 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700876 if err != nil {
877 oltLogger.WithFields(log.Fields{
878 "OnuId": flow.OnuId,
879 "IntfId": flow.AccessIntfId,
880 "err": err,
881 }).Error("Can't find Onu")
882 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700883
884 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700885 Type: FlowUpdate,
886 Data: OnuFlowUpdateMessage{
887 PonPortID: pon.ID,
888 OnuID: onu.ID,
889 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700890 },
891 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700892 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700893 }
894
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700895 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700896}
897
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700898func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
899 oltLogger.Tracef("received FlowRemove")
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700900 // TODO store flows somewhere
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700901 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700902}
903
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700904func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo18859852020-01-15 13:33:57 -0800905 res := openolt.Heartbeat{HeartbeatSignature: uint32(time.Now().Unix())}
906 oltLogger.WithFields(log.Fields{
907 "signature": res.HeartbeatSignature,
908 }).Trace("HeartbeatCheck")
909 return &res, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700910}
911
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700912func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700913
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700914 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700915 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700916 "PonPorts": o.NumPon,
917 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700918 devinfo := new(openolt.DeviceInfo)
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100919 devinfo.Vendor = common.Options.Olt.Vendor
920 devinfo.Model = common.Options.Olt.Model
921 devinfo.HardwareVersion = common.Options.Olt.HardwareVersion
922 devinfo.FirmwareVersion = common.Options.Olt.FirmwareVersion
923 devinfo.Technology = common.Options.Olt.Technology
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700924 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700925 devinfo.OnuIdStart = 1
926 devinfo.OnuIdEnd = 255
927 devinfo.AllocIdStart = 1024
928 devinfo.AllocIdEnd = 16383
929 devinfo.GemportIdStart = 1024
930 devinfo.GemportIdEnd = 65535
931 devinfo.FlowIdStart = 1
932 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -0700933 devinfo.DeviceSerialNumber = o.SerialNumber
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100934 devinfo.DeviceId = common.Options.Olt.DeviceId
Matteo Scandolo4747d292019-08-05 11:50:18 -0700935
936 return devinfo, nil
937}
938
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700939func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700940 pon, _ := o.GetPonById(omci_msg.IntfId)
941 onu, _ := pon.GetOnuById(omci_msg.OnuId)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700942 oltLogger.WithFields(log.Fields{
943 "IntfId": onu.PonPortID,
944 "OnuId": onu.ID,
945 "OnuSn": onu.Sn(),
946 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700947 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700948 Type: OMCI,
949 Data: OmciMessage{
950 OnuSN: onu.SerialNumber,
951 OnuID: onu.ID,
952 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700953 },
954 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700955 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700956 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700957}
958
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700959func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700960 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700961 if err != nil {
962 oltLogger.WithFields(log.Fields{
963 "OnuId": onuPkt.OnuId,
964 "IntfId": onuPkt.IntfId,
965 "err": err,
966 }).Error("Can't find PonPort")
967 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700968 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700969 if err != nil {
970 oltLogger.WithFields(log.Fields{
971 "OnuId": onuPkt.OnuId,
972 "IntfId": onuPkt.IntfId,
973 "err": err,
974 }).Error("Can't find Onu")
975 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700976
Matteo Scandolo075b1892019-10-07 12:11:07 -0700977 oltLogger.WithFields(log.Fields{
978 "IntfId": onu.PonPortID,
979 "OnuId": onu.ID,
980 "OnuSn": onu.Sn(),
981 }).Tracef("Received OnuPacketOut")
982
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700983 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700984 pktType, err := packetHandlers.IsEapolOrDhcp(rawpkt)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700985
Matteo Scandolo075b1892019-10-07 12:11:07 -0700986 msg := Message{
987 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700988 Data: OnuPacketMessage{
Matteo Scandolo075b1892019-10-07 12:11:07 -0700989 IntfId: onuPkt.IntfId,
990 OnuId: onuPkt.OnuId,
991 Packet: rawpkt,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700992 Type: pktType,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700993 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700994 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700995 onu.Channel <- msg
996
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700997 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700998}
999
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001000func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolod02b79b2019-12-05 16:42:13 -08001001 oltLogger.WithFields(log.Fields{
1002 "oltId": o.ID,
1003 }).Info("Shutting down")
1004 go o.RestartOLT()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001005 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001006}
1007
1008func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Pragya Arya6a708d62020-01-01 17:17:20 +05301009 oltLogger.WithFields(log.Fields{
1010 "oltId": o.ID,
1011 }).Info("Received ReenableOlt request from VOLTHA")
1012
Pragya Arya1881df02020-01-29 18:05:01 +05301013 // enable OLT
1014 oltMsg := Message{
1015 Type: OltIndication,
1016 Data: OltIndicationMessage{
1017 OperState: UP,
1018 },
Pragya Arya6a708d62020-01-01 17:17:20 +05301019 }
Pragya Arya1881df02020-01-29 18:05:01 +05301020 o.channel <- oltMsg
Pragya Arya6a708d62020-01-01 17:17:20 +05301021
Pragya Arya1881df02020-01-29 18:05:01 +05301022 for _, pon := range o.Pons {
1023 if pon.InternalState.Current() == "disabled" {
1024 msg := Message{
1025 Type: PonIndication,
1026 Data: PonIndicationMessage{
1027 OperState: UP,
1028 PonPortID: pon.ID,
1029 },
1030 }
1031 o.channel <- msg
1032 }
1033 }
Pragya Arya6a708d62020-01-01 17:17:20 +05301034
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001035 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001036}
1037
1038func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001039 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
1040
Zdravko Bozakov681364d2019-11-10 14:28:46 +01001041 o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001042 // NOTE should we return an error if sendNniPakcet fails?
1043 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001044}
1045
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001046func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001047 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001048 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001049}
1050
Matteo Scandolo4747d292019-08-05 11:50:18 -07001051func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001052 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001053 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001054}
1055
1056func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001057 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001058 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -07001059}
1060
1061func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001062 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001063 return new(openolt.Empty), nil
1064}
1065
1066func (s OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001067 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001068 return new(openolt.Empty), nil
1069}
1070
1071func (s OltDevice) CreateTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001072 oltLogger.Info("received CreateTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001073 return new(openolt.Empty), nil
1074}
1075
1076func (s OltDevice) RemoveTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001077 oltLogger.Info("received RemoveTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001078 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001079}
Scott Baker41724b82020-01-21 19:54:53 -08001080
1081// assumes caller has properly formulated an openolt.AlarmIndication
1082func (o OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
1083 msg := Message{
1084 Type: AlarmIndication,
1085 Data: ind,
1086 }
1087
1088 o.channel <- msg
1089 return nil
1090}