blob: 955d2adb4a541311fdcd1d19d53242c6a2821dac [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"
Anand S Katti09541352020-01-29 15:54:01 +053036 tech_profile "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 Arya2225f202020-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
Anand S Katti09541352020-01-29 15:54:01 +053072 enablePerf bool
Matteo Scandolo4747d292019-08-05 11:50:18 -070073}
74
Matteo Scandolo27428702019-10-11 16:21:16 -070075var olt OltDevice
Zdravko Bozakov681364d2019-11-10 14:28:46 +010076var oltServer *grpc.Server
Matteo Scandolo84f7d482019-08-08 19:00:47 -070077
Matteo Scandolo27428702019-10-11 16:21:16 -070078func GetOLT() *OltDevice {
79 return &olt
Matteo Scandolo84f7d482019-08-08 19:00:47 -070080}
81
Anand S Katti09541352020-01-29 15:54:01 +053082func CreateOLT(oltId int, nni int, pon int, onuPerPon int, sTag int, cTagInit int, auth bool, dhcp bool, delay int, ca string, enablePerf bool, isMock bool) *OltDevice {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070083 oltLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070084 "ID": oltId,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070085 "NumNni": nni,
86 "NumPon": pon,
87 "NumOnuPerPon": onuPerPon,
Matteo Scandolo4747d292019-08-05 11:50:18 -070088 }).Debug("CreateOLT")
89
Matteo Scandolo84f7d482019-08-08 19:00:47 -070090 olt = OltDevice{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070091 ID: oltId,
92 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", oltId),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070093 OperState: getOperStateFSM(func(e *fsm.Event) {
94 oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
95 }),
Zdravko Bozakov681364d2019-11-10 14:28:46 +010096 NumNni: nni,
97 NumPon: pon,
98 NumOnuPerPon: onuPerPon,
99 Pons: []*PonPort{},
100 Nnis: []*NniPort{},
101 Delay: delay,
Anand S Katti09541352020-01-29 15:54:01 +0530102 enablePerf: enablePerf,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700103 }
104
Pragya Arya2225f202020-01-29 18:05:01 +0530105 if val, ok := ControlledActivationModes[ca]; ok {
106 olt.ControlledActivation = val
107 } else {
108 oltLogger.Warn("Unknown ControlledActivation Mode given, running in Default mode")
109 olt.ControlledActivation = Default
110 }
111
Matteo Scandolo4747d292019-08-05 11:50:18 -0700112 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700113 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700114 olt.InternalState = fsm.NewFSM(
115 "created",
116 fsm.Events{
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800117 {Name: "initialize", Src: []string{"created", "deleted"}, Dst: "initialized"},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100118 {Name: "enable", Src: []string{"initialized", "disabled"}, Dst: "enabled"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700119 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
Mahir Gunyel6dad4452020-01-06 12:59:04 -0800120 //delete event in enabled state below is for reboot OLT case.
121 {Name: "delete", Src: []string{"disabled", "enabled"}, Dst: "deleted"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700122 },
123 fsm.Callbacks{
124 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700125 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700126 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100127 "enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
Matteo Scandolo4747d292019-08-05 11:50:18 -0700128 },
129 )
130
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700131 if isMock != true {
132 // create NNI Port
133 nniPort, err := CreateNNI(&olt)
134 if err != nil {
135 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
136 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700137
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700138 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700139 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700140
Matteo Scandolo4747d292019-08-05 11:50:18 -0700141 // create PON ports
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700142 availableCTag := cTagInit
Matteo Scandolo4747d292019-08-05 11:50:18 -0700143 for i := 0; i < pon; i++ {
Pragya Arya2225f202020-01-29 18:05:01 +0530144 p := CreatePonPort(&olt, uint32(i))
Matteo Scandolo4747d292019-08-05 11:50:18 -0700145
146 // create ONU devices
147 for j := 0; j < onuPerPon; j++ {
Matteo Scandolo583f17d2020-02-13 10:35:17 -0800148 delay := time.Duration(olt.Delay*j) * time.Millisecond
Pragya Arya2225f202020-01-29 18:05:01 +0530149 o := CreateONU(&olt, *p, uint32(j+1), sTag, availableCTag, auth, dhcp, delay, isMock)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700150 p.Onus = append(p.Onus, o)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700151 availableCTag = availableCTag + 1
Matteo Scandolo4747d292019-08-05 11:50:18 -0700152 }
153
Pragya Arya6a708d62020-01-01 17:17:20 +0530154 olt.Pons = append(olt.Pons, p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700155 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100156
Matteo Scandolod32c3822019-11-26 15:57:46 -0700157 if isMock != true {
158 if err := olt.InternalState.Event("initialize"); err != nil {
159 log.Errorf("Error initializing OLT: %v", err)
160 return nil
161 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100162 }
163
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700164 return &olt
165}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700166
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100167func (o *OltDevice) InitOlt() error {
168
169 if oltServer == nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800170 oltServer, _ = o.newOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100171 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800172 // FIXME there should never be a server running if we are initializing the OLT
173 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100174 }
175
176 // create new channel for processOltMessages Go routine
177 o.channel = make(chan Message)
178
179 o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
180 // FIXME we are assuming we have only one NNI
181 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800182 // NOTE we want to make sure the state is down when we initialize the OLT,
183 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
184 // in-band management
185 o.Nnis[0].OperState.SetState("down")
186 ch, handle, err := o.Nnis[0].NewVethChan()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100187 if err == nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800188 oltLogger.WithFields(log.Fields{
189 "Type": o.Nnis[0].Type,
190 "IntfId": o.Nnis[0].ID,
191 "OperState": o.Nnis[0].OperState.Current(),
192 }).Info("NNI Channel created")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100193 o.nniPktInChannel = ch
Matteo Scandolo401503a2019-12-11 14:48:14 -0800194 o.nniHandle = handle
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100195 } else {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800196 oltLogger.Errorf("Error getting NNI channel: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100197 }
198 }
199
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100200 return nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700201}
202
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800203func (o *OltDevice) RestartOLT() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100204
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800205 rebootDelay := common.Options.Olt.OltRebootDelay
206
207 oltLogger.WithFields(log.Fields{
208 "oltId": o.ID,
209 }).Infof("Simulating OLT restart... (%ds)", rebootDelay)
210
211 // transition internal state to deleted
212 if err := o.InternalState.Event("delete"); err != nil {
213 oltLogger.WithFields(log.Fields{
214 "oltId": o.ID,
215 }).Errorf("Error deleting OLT: %v", err)
216 return err
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100217 }
218
219 // TODO handle hard poweroff (i.e. no indications sent to Voltha) vs soft poweroff
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800220 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
221 if err := o.StopOltServer(); err != nil {
Pragya Arya2225f202020-01-29 18:05:01 +0530222 oltLogger.Errorf("Error in stopping OLT server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100223 return err
224 }
225
Pragya Arya2225f202020-01-29 18:05:01 +0530226 for _, pon := range olt.Pons {
227 msg := Message{
228 Type: PonIndication,
229 Data: PonIndicationMessage{
230 OperState: DOWN,
231 PonPortID: pon.ID,
232 },
233 }
234 o.channel <- msg
235
236 for _, onu := range pon.Onus {
237 if onu.InternalState.Current() != "initialized" {
238 onu.InternalState.Event("disable")
239 }
240 }
241 }
242
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100243 // terminate the OLT's processOltMessages go routine
244 close(o.channel)
245 // terminate the OLT's processNniPacketIns go routine
Andy Bavier421f4d52020-01-21 15:39:22 -0700246 go o.nniHandle.Close()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100247 close(o.nniPktInChannel)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100248
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100249 time.Sleep(time.Duration(rebootDelay) * time.Second)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100250
251 if err := o.InternalState.Event("initialize"); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800252 oltLogger.WithFields(log.Fields{
253 "oltId": o.ID,
254 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100255 return err
256 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800257 oltLogger.WithFields(log.Fields{
258 "oltId": o.ID,
259 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100260 return nil
261}
262
263// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800264func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100265 address := common.Options.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700266 lis, err := net.Listen("tcp", address)
267 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700268 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700269 }
270 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100271
Matteo Scandolo4747d292019-08-05 11:50:18 -0700272 openolt.RegisterOpenoltServer(grpcServer, o)
273
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100274 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700275
Matteo Scandolo4747d292019-08-05 11:50:18 -0700276 go grpcServer.Serve(lis)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100277 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700278
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100279 return grpcServer, nil
280}
281
282// StopOltServer stops the OpenOLT grpc server
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800283func (o *OltDevice) StopOltServer() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100284 // TODO handle poweroff vs graceful shutdown
285 if oltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800286 oltLogger.WithFields(log.Fields{
287 "oltId": o.SerialNumber,
288 }).Warnf("Stopping OLT gRPC server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100289 oltServer.Stop()
290 oltServer = nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700291 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800292
Matteo Scandolo4747d292019-08-05 11:50:18 -0700293 return nil
294}
295
296// Device Methods
297
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100298// Enable implements the OpenOLT EnableIndicationServer functionality
299func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700300 oltLogger.Debug("Enable OLT called")
Pragya Arya2225f202020-01-29 18:05:01 +0530301 rebootFlag := false
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700302
David Bainbridge103cf022019-12-16 20:11:35 +0000303 // If enabled has already been called then an enabled context has
304 // been created. If this is the case then we want to cancel all the
305 // proessing loops associated with that enable before we recreate
306 // new ones
307 o.Lock()
308 if o.enableContext != nil && o.enableContextCancel != nil {
309 o.enableContextCancel()
Pragya Arya2225f202020-01-29 18:05:01 +0530310 rebootFlag = true
David Bainbridge103cf022019-12-16 20:11:35 +0000311 }
312 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
313 o.Unlock()
314
Matteo Scandolo4747d292019-08-05 11:50:18 -0700315 wg := sync.WaitGroup{}
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800316 wg.Add(3)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700317
Pragya Arya1cbefa42020-01-13 12:15:29 +0530318 o.OpenoltStream = &stream
319
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100320 // create Go routine to process all OLT events
David Bainbridge103cf022019-12-16 20:11:35 +0000321 go o.processOltMessages(o.enableContext, stream, &wg)
322 go o.processNniPacketIns(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700323
324 // enable the OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100325 oltMsg := Message{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700326 Type: OltIndication,
327 Data: OltIndicationMessage{
328 OperState: UP,
329 },
330 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100331 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700332
333 // send NNI Port Indications
334 for _, nni := range o.Nnis {
335 msg := Message{
336 Type: NniIndication,
337 Data: NniIndicationMessage{
338 OperState: UP,
339 NniPortID: nni.ID,
340 },
341 }
342 o.channel <- msg
343 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100344
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800345 go o.processOmciMessages(o.enableContext, stream, &wg)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100346
Pragya Arya2225f202020-01-29 18:05:01 +0530347 if rebootFlag == true {
348 for _, pon := range o.Pons {
349 if pon.InternalState.Current() == "disabled" {
350 msg := Message{
351 Type: PonIndication,
352 Data: PonIndicationMessage{
353 OperState: UP,
354 PonPortID: pon.ID,
355 },
356 }
357 o.channel <- msg
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000358 }
Pragya Arya2225f202020-01-29 18:05:01 +0530359 }
360 } else {
361
362 // 1. controlledActivation == Default: Send both PON and ONUs indications
363 // 2. controlledActivation == only-onu: that means only ONUs will be controlled activated, so auto send PON indications
364
365 if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
366 // send PON Port indications
367 for _, pon := range o.Pons {
368 msg := Message{
369 Type: PonIndication,
370 Data: PonIndicationMessage{
371 OperState: UP,
372 PonPortID: pon.ID,
373 },
374 }
375 o.channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700376 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700377 }
378 }
379
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800380 oltLogger.Debug("Enable OLT Done")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700381 wg.Wait()
382 return nil
383}
384
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800385func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400386 ch := omcisim.GetChannel()
387
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100388 oltLogger.Debug("Starting OMCI Indication Channel")
William Kurkian9dadc5b2019-10-22 13:51:57 -0400389
David Bainbridge103cf022019-12-16 20:11:35 +0000390loop:
391 for {
392 select {
393 case <-ctx.Done():
394 oltLogger.Debug("OMCI processing canceled via context")
395 break loop
396 case message, ok := <-ch:
397 if !ok || ctx.Err() != nil {
398 oltLogger.Debug("OMCI processing canceled via channel close")
399 break loop
400 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800401
402 oltLogger.WithFields(log.Fields{
403 "messageType": message.Type,
404 "OnuId": message.Data.OnuId,
405 "IntfId": message.Data.IntfId,
406 }).Info("Received message on OMCI Sim channel")
407
David Bainbridge103cf022019-12-16 20:11:35 +0000408 onuId := message.Data.OnuId
409 intfId := message.Data.IntfId
410 onu, err := o.FindOnuById(intfId, onuId)
411 if err != nil {
412 oltLogger.Errorf("Failed to find onu: %v", err)
413 continue
414 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800415 go onu.processOmciMessage(message, stream)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400416 }
William Kurkian9dadc5b2019-10-22 13:51:57 -0400417 }
David Bainbridge103cf022019-12-16 20:11:35 +0000418
419 wg.Done()
William Kurkian9dadc5b2019-10-22 13:51:57 -0400420}
421
Matteo Scandolo4747d292019-08-05 11:50:18 -0700422// Helpers method
423
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700424func (o OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700425 for _, pon := range o.Pons {
426 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700427 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700428 }
429 }
430 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
431}
432
433func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
434 for _, nni := range o.Nnis {
435 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700436 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700437 }
438 }
439 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
440}
441
Scott Baker41724b82020-01-21 19:54:53 -0800442func (o *OltDevice) sendAlarmIndication(alarmInd *openolt.AlarmIndication, stream openolt.Openolt_EnableIndicationServer) {
443 data := &openolt.Indication_AlarmInd{AlarmInd: alarmInd}
444 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
445 oltLogger.Errorf("Failed to send Alarm Indication: %v", err)
446 return
447 }
448
449 oltLogger.WithFields(log.Fields{
450 "AlarmIndication": alarmInd,
451 }).Debug("Sent Indication_AlarmInd")
452}
453
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100454func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700455 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
456 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700457 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800458 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700459 }
460
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700461 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700462 "OperState": msg.OperState,
463 }).Debug("Sent Indication_OltInd")
464}
465
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100466func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700467 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800468 if msg.OperState == UP {
469 if err := nni.OperState.Event("enable"); err != nil {
470 log.WithFields(log.Fields{
471 "Type": nni.Type,
472 "IntfId": nni.ID,
473 "OperState": nni.OperState.Current(),
474 }).Errorf("Can't move NNI Port to enabled state: %v", err)
475 }
476 } else if msg.OperState == DOWN {
477 if err := nni.OperState.Event("disable"); err != nil {
478 log.WithFields(log.Fields{
479 "Type": nni.Type,
480 "IntfId": nni.ID,
481 "OperState": nni.OperState.Current(),
482 }).Errorf("Can't move NNI Port to disable state: %v", err)
483 }
484 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700485 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700486 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700487 Type: nni.Type,
488 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700489 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700490 }}
491
492 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700493 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800494 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700495 }
496
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700497 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700498 "Type": nni.Type,
499 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700500 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700501 }).Debug("Sent Indication_IntfOperInd for NNI")
502}
503
Pragya Arya2225f202020-01-29 18:05:01 +0530504func (o *OltDevice) sendPonIndication(ponPortID uint32) {
505
506 stream := *o.OpenoltStream
507 pon, _ := o.GetPonById(ponPortID)
508 // Send IntfIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700509 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700510 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700511 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700512 }}
513
514 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700515 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800516 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700517 }
518
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700519 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700520 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700521 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700522 }).Debug("Sent Indication_IntfInd")
523
Pragya Arya2225f202020-01-29 18:05:01 +0530524 // Send IntfOperIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700525 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700526 Type: pon.Type,
527 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700528 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700529 }}
530
531 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700532 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800533 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700534 }
535
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700536 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700537 "Type": pon.Type,
538 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700539 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700540 }).Debug("Sent Indication_IntfOperInd for PON")
541}
542
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100543// processOltMessages handles messages received over the OpenOLT interface
David Bainbridge103cf022019-12-16 20:11:35 +0000544func (o *OltDevice) processOltMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100545 oltLogger.Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000546 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700547
David Bainbridge103cf022019-12-16 20:11:35 +0000548loop:
549 for {
550 select {
551 case <-ctx.Done():
552 oltLogger.Debug("OLT Indication processing canceled via context")
553 break loop
554 case message, ok := <-ch:
555 if !ok || ctx.Err() != nil {
556 oltLogger.Debug("OLT Indication processing canceled via closed channel")
557 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700558 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700559
David Bainbridge103cf022019-12-16 20:11:35 +0000560 oltLogger.WithFields(log.Fields{
561 "oltId": o.ID,
562 "messageType": message.Type,
563 }).Trace("Received message")
564
565 switch message.Type {
566 case OltIndication:
567 msg, _ := message.Data.(OltIndicationMessage)
568 if msg.OperState == UP {
569 o.InternalState.Event("enable")
570 o.OperState.Event("enable")
571 } else if msg.OperState == DOWN {
572 o.InternalState.Event("disable")
573 o.OperState.Event("disable")
574 }
575 o.sendOltIndication(msg, stream)
Scott Baker41724b82020-01-21 19:54:53 -0800576 case AlarmIndication:
577 alarmInd, _ := message.Data.(*openolt.AlarmIndication)
578 o.sendAlarmIndication(alarmInd, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000579 case NniIndication:
580 msg, _ := message.Data.(NniIndicationMessage)
581 o.sendNniIndication(msg, stream)
582 case PonIndication:
583 msg, _ := message.Data.(PonIndicationMessage)
Pragya Arya2225f202020-01-29 18:05:01 +0530584 pon, _ := o.GetPonById(msg.PonPortID)
585 if msg.OperState == UP {
586 pon.OperState.Event("enable")
587 pon.InternalState.Event("enable")
588 } else if msg.OperState == DOWN {
589 pon.OperState.Event("disable")
590 pon.InternalState.Event("disable")
591 }
David Bainbridge103cf022019-12-16 20:11:35 +0000592 default:
593 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
594 }
595 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700596 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100597 wg.Done()
598 oltLogger.Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700599}
600
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100601// processNniPacketIns handles messages received over the NNI interface
David Bainbridge103cf022019-12-16 20:11:35 +0000602func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700603 oltLogger.WithFields(log.Fields{
604 "nniChannel": o.nniPktInChannel,
Matteo Scandolo401503a2019-12-11 14:48:14 -0800605 }).Debug("Started Processing Packets arriving from the NNI")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700606 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700607
David Bainbridge103cf022019-12-16 20:11:35 +0000608 ch := o.nniPktInChannel
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700609
David Bainbridge103cf022019-12-16 20:11:35 +0000610loop:
611 for {
612 select {
613 case <-ctx.Done():
614 oltLogger.Debug("NNI Indication processing canceled via context")
615 break loop
616 case message, ok := <-ch:
617 if !ok || ctx.Err() != nil {
618 oltLogger.Debug("NNI Indication processing canceled via channel closed")
619 break loop
620 }
621 oltLogger.Tracef("Received packets on NNI Channel")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700622
David Bainbridge103cf022019-12-16 20:11:35 +0000623 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700624
David Bainbridge103cf022019-12-16 20:11:35 +0000625 if err != nil {
626 log.WithFields(log.Fields{
627 "IntfType": "nni",
628 "IntfId": nniId,
629 "Pkt": message.Pkt.Data(),
630 }).Error("Can't find Dst MacAddress in packet")
631 return
632 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700633
David Bainbridge103cf022019-12-16 20:11:35 +0000634 onu, err := o.FindOnuByMacAddress(onuMac)
635 if err != nil {
636 log.WithFields(log.Fields{
637 "IntfType": "nni",
638 "IntfId": nniId,
639 "Pkt": message.Pkt.Data(),
640 "MacAddress": onuMac.String(),
641 }).Error("Can't find ONU with MacAddress")
642 return
643 }
644
645 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
646 if err != nil {
647 log.Error("Fail to add double tag to packet")
648 }
649
650 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
651 IntfType: "nni",
652 IntfId: nniId,
653 Pkt: doubleTaggedPkt.Data()}}
654 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
655 oltLogger.WithFields(log.Fields{
656 "IntfType": data.PktInd.IntfType,
657 "IntfId": nniId,
658 "Pkt": doubleTaggedPkt.Data(),
659 }).Errorf("Fail to send PktInd indication: %v", err)
660 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700661 oltLogger.WithFields(log.Fields{
662 "IntfType": data.PktInd.IntfType,
663 "IntfId": nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700664 "Pkt": doubleTaggedPkt.Data(),
David Bainbridge103cf022019-12-16 20:11:35 +0000665 "OnuSn": onu.Sn(),
666 }).Tracef("Sent PktInd indication")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700667 }
668 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100669 wg.Done()
670 oltLogger.WithFields(log.Fields{
671 "nniChannel": o.nniPktInChannel,
672 }).Warn("Stopped handling NNI Channel")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700673}
674
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700675// returns an ONU with a given Serial Number
676func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200677 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700678 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700679 for _, pon := range o.Pons {
680 for _, onu := range pon.Onus {
681 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700682 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700683 }
684 }
685 }
686
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700687 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-serial-number-%s", serialNumber))
688}
689
William Kurkian9dadc5b2019-10-22 13:51:57 -0400690// returns an ONU with a given interface/Onu Id
691func (o OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200692 // TODO this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400693 // memoizing it will remove the bottleneck
694 for _, pon := range o.Pons {
695 if pon.ID == intfId {
696 for _, onu := range pon.Onus {
697 if onu.ID == onuId {
698 return onu, nil
699 }
700 }
701 }
702 }
703 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-id-%v-%v", intfId, onuId))
704}
705
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700706// returns an ONU with a given Mac Address
707func (o OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200708 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700709 // memoizing it will remove the bottleneck
710 for _, pon := range o.Pons {
711 for _, onu := range pon.Onus {
712 if onu.HwAddress.String() == mac.String() {
Matteo Scandolo27428702019-10-11 16:21:16 -0700713 return onu, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700714 }
715 }
716 }
717
718 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-mac-address-%s", mac))
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700719}
720
Matteo Scandolo4747d292019-08-05 11:50:18 -0700721// GRPC Endpoints
722
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700723func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700724 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700725 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700726 }).Info("Received ActivateOnu call from VOLTHA")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700727
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700728 pon, _ := o.GetPonById(onu.IntfId)
729 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
William Kurkian0418bc82019-11-06 12:16:24 -0500730 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700731
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700732 if err := _onu.OperState.Event("enable"); err != nil {
733 oltLogger.WithFields(log.Fields{
734 "IntfId": _onu.PonPortID,
735 "OnuSn": _onu.Sn(),
736 "OnuId": _onu.ID,
737 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700738 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700739 if err := _onu.InternalState.Event("enable"); err != nil {
740 oltLogger.WithFields(log.Fields{
741 "IntfId": _onu.PonPortID,
742 "OnuSn": _onu.Sn(),
743 "OnuId": _onu.ID,
744 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
745 }
746
747 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
748
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700749 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700750}
751
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700752func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700753 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700754 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700755}
756
Pragya Arya1cbefa42020-01-13 12:15:29 +0530757func (o OltDevice) DeleteOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
758 oltLogger.WithFields(log.Fields{
759 "IntfId": onu.IntfId,
760 "OnuId": onu.OnuId,
761 }).Info("Received DeleteOnu call from VOLTHA")
762
763 pon, err := o.GetPonById(onu.IntfId)
764 if err != nil {
765 oltLogger.WithFields(log.Fields{
766 "OnuId": onu.OnuId,
767 "IntfId": onu.IntfId,
768 "err": err,
769 }).Error("Can't find PonPort")
770 }
771 _onu, err := pon.GetOnuById(onu.OnuId)
772 if err != nil {
773 oltLogger.WithFields(log.Fields{
774 "OnuId": onu.OnuId,
775 "IntfId": onu.IntfId,
776 "err": err,
777 }).Error("Can't find Onu")
778 }
779
780 if err := _onu.InternalState.Event("initialize"); err != nil {
781 oltLogger.WithFields(log.Fields{
782 "IntfId": _onu.PonPortID,
783 "OnuSn": _onu.Sn(),
784 "OnuId": _onu.ID,
785 }).Infof("Failed to transition ONU to initialized state: %s", err.Error())
786 }
787
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700788 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700789}
790
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700791func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700792 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800793 oltLogger.WithFields(log.Fields{
794 "oltId": o.ID,
795 }).Info("Disabling OLT")
796
Matteo Scandolo401503a2019-12-11 14:48:14 -0800797 for _, pon := range o.Pons {
Pragya Arya2225f202020-01-29 18:05:01 +0530798 if pon.InternalState.Current() == "enabled" {
799 // disable PONs
800 msg := Message{
801 Type: PonIndication,
802 Data: PonIndicationMessage{
803 OperState: DOWN,
804 PonPortID: pon.ID,
805 },
806 }
807 o.channel <- msg
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800808 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800809 }
810
Matteo Scandolo401503a2019-12-11 14:48:14 -0800811 // Note that we are not disabling the NNI as the real OLT does not.
812 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800813
814 // disable OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100815 oltMsg := Message{
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700816 Type: OltIndication,
817 Data: OltIndicationMessage{
818 OperState: DOWN,
819 },
820 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100821 o.channel <- oltMsg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700822 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700823}
824
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700825func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700826 oltLogger.Error("DisablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700827 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700828}
829
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100830func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700831 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700832 o.Enable(stream)
833 return nil
834}
835
Pragya Arya2225f202020-01-29 18:05:01 +0530836func (o OltDevice) EnablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
837 oltLogger.Errorf("EnablePonIf request received for PON %d", intf.IntfId)
838 ponID := intf.GetIntfId()
839 msg := Message{
840 Type: PonIndication,
841 Data: PonIndicationMessage{
842 OperState: UP,
843 PonPortID: ponID,
844 },
845 }
846 o.channel <- msg
847
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700848 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700849}
850
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700851func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700852 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700853 "IntfId": flow.AccessIntfId,
854 "OnuId": flow.OnuId,
855 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700856 "InnerVlan": flow.Classifier.IVid,
857 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700858 "FlowType": flow.FlowType,
859 "FlowId": flow.FlowId,
860 "UniID": flow.UniId,
861 "PortNo": flow.PortNo,
862 }).Tracef("OLT receives Flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700863 // TODO optionally store flows somewhere
864
865 if flow.AccessIntfId == -1 {
866 oltLogger.WithFields(log.Fields{
867 "FlowId": flow.FlowId,
868 }).Debugf("This is an OLT flow")
869 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700870 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700871 if err != nil {
872 oltLogger.WithFields(log.Fields{
873 "OnuId": flow.OnuId,
874 "IntfId": flow.AccessIntfId,
875 "err": err,
876 }).Error("Can't find PonPort")
877 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700878 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700879 if err != nil {
880 oltLogger.WithFields(log.Fields{
881 "OnuId": flow.OnuId,
882 "IntfId": flow.AccessIntfId,
883 "err": err,
884 }).Error("Can't find Onu")
885 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700886
887 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700888 Type: FlowUpdate,
889 Data: OnuFlowUpdateMessage{
890 PonPortID: pon.ID,
891 OnuID: onu.ID,
892 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700893 },
894 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700895 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700896 }
897
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700898 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700899}
900
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700901func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
902 oltLogger.Tracef("received FlowRemove")
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700903 // TODO store flows somewhere
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700904 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700905}
906
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700907func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo18859852020-01-15 13:33:57 -0800908 res := openolt.Heartbeat{HeartbeatSignature: uint32(time.Now().Unix())}
909 oltLogger.WithFields(log.Fields{
910 "signature": res.HeartbeatSignature,
911 }).Trace("HeartbeatCheck")
912 return &res, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700913}
914
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700915func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700916
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700917 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700918 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700919 "PonPorts": o.NumPon,
920 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700921 devinfo := new(openolt.DeviceInfo)
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100922 devinfo.Vendor = common.Options.Olt.Vendor
923 devinfo.Model = common.Options.Olt.Model
924 devinfo.HardwareVersion = common.Options.Olt.HardwareVersion
925 devinfo.FirmwareVersion = common.Options.Olt.FirmwareVersion
926 devinfo.Technology = common.Options.Olt.Technology
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700927 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700928 devinfo.OnuIdStart = 1
929 devinfo.OnuIdEnd = 255
930 devinfo.AllocIdStart = 1024
931 devinfo.AllocIdEnd = 16383
932 devinfo.GemportIdStart = 1024
933 devinfo.GemportIdEnd = 65535
934 devinfo.FlowIdStart = 1
935 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -0700936 devinfo.DeviceSerialNumber = o.SerialNumber
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100937 devinfo.DeviceId = common.Options.Olt.DeviceId
Matteo Scandolo4747d292019-08-05 11:50:18 -0700938
939 return devinfo, nil
940}
941
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700942func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700943 pon, _ := o.GetPonById(omci_msg.IntfId)
944 onu, _ := pon.GetOnuById(omci_msg.OnuId)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700945 oltLogger.WithFields(log.Fields{
946 "IntfId": onu.PonPortID,
947 "OnuId": onu.ID,
948 "OnuSn": onu.Sn(),
949 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700950 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700951 Type: OMCI,
952 Data: OmciMessage{
953 OnuSN: onu.SerialNumber,
954 OnuID: onu.ID,
955 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700956 },
957 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700958 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700959 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700960}
961
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700962func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700963 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700964 if err != nil {
965 oltLogger.WithFields(log.Fields{
966 "OnuId": onuPkt.OnuId,
967 "IntfId": onuPkt.IntfId,
968 "err": err,
969 }).Error("Can't find PonPort")
970 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700971 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700972 if err != nil {
973 oltLogger.WithFields(log.Fields{
974 "OnuId": onuPkt.OnuId,
975 "IntfId": onuPkt.IntfId,
976 "err": err,
977 }).Error("Can't find Onu")
978 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700979
Matteo Scandolo075b1892019-10-07 12:11:07 -0700980 oltLogger.WithFields(log.Fields{
981 "IntfId": onu.PonPortID,
982 "OnuId": onu.ID,
983 "OnuSn": onu.Sn(),
984 }).Tracef("Received OnuPacketOut")
985
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700986 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700987 pktType, err := packetHandlers.IsEapolOrDhcp(rawpkt)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700988
Matteo Scandolo075b1892019-10-07 12:11:07 -0700989 msg := Message{
990 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700991 Data: OnuPacketMessage{
Matteo Scandolo075b1892019-10-07 12:11:07 -0700992 IntfId: onuPkt.IntfId,
993 OnuId: onuPkt.OnuId,
994 Packet: rawpkt,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700995 Type: pktType,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700996 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700997 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700998 onu.Channel <- msg
999
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001000 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001001}
1002
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001003func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolod02b79b2019-12-05 16:42:13 -08001004 oltLogger.WithFields(log.Fields{
1005 "oltId": o.ID,
1006 }).Info("Shutting down")
1007 go o.RestartOLT()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001008 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001009}
1010
1011func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Pragya Arya6a708d62020-01-01 17:17:20 +05301012 oltLogger.WithFields(log.Fields{
1013 "oltId": o.ID,
1014 }).Info("Received ReenableOlt request from VOLTHA")
1015
Pragya Arya2225f202020-01-29 18:05:01 +05301016 // enable OLT
1017 oltMsg := Message{
1018 Type: OltIndication,
1019 Data: OltIndicationMessage{
1020 OperState: UP,
1021 },
Pragya Arya1881df02020-01-29 18:05:01 +05301022 }
Pragya Arya2225f202020-01-29 18:05:01 +05301023 o.channel <- oltMsg
Pragya Arya6a708d62020-01-01 17:17:20 +05301024
Pragya Arya2225f202020-01-29 18:05:01 +05301025 for _, pon := range o.Pons {
1026 if pon.InternalState.Current() == "disabled" {
1027 msg := Message{
1028 Type: PonIndication,
1029 Data: PonIndicationMessage{
1030 OperState: UP,
1031 PonPortID: pon.ID,
1032 },
1033 }
1034 o.channel <- msg
1035 }
1036 }
Matteo Scandoloe60a5052020-02-07 00:31:14 +00001037
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001038 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001039}
1040
1041func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001042 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
1043
Zdravko Bozakov681364d2019-11-10 14:28:46 +01001044 o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001045 // NOTE should we return an error if sendNniPakcet fails?
1046 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001047}
1048
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001049func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001050 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001051 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001052}
1053
Matteo Scandolo4747d292019-08-05 11:50:18 -07001054func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001055 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001056 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001057}
1058
1059func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001060 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001061 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -07001062}
1063
1064func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001065 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001066 return new(openolt.Empty), nil
1067}
1068
1069func (s OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001070 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001071 return new(openolt.Empty), nil
1072}
1073
Anand S Katti09541352020-01-29 15:54:01 +05301074func (s OltDevice) CreateTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
1075 oltLogger.WithFields(log.Fields{
1076 "OnuId": trafficSchedulers.OnuId,
1077 "IntfId": trafficSchedulers.IntfId,
1078 "OnuPortNo": trafficSchedulers.PortNo,
1079 }).Info("received CreateTrafficSchedulers")
1080
1081 if !s.enablePerf {
1082 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1083 if err != nil {
1084 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1085 return new(openolt.Empty), err
1086 }
1087 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1088 if err != nil {
1089 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1090 return new(openolt.Empty), err
1091 }
1092 onu.TrafficSchedulers = trafficSchedulers
1093 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001094 return new(openolt.Empty), nil
1095}
1096
Anand S Katti09541352020-01-29 15:54:01 +05301097func (s OltDevice) RemoveTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
1098 oltLogger.WithFields(log.Fields{
1099 "OnuId": trafficSchedulers.OnuId,
1100 "IntfId": trafficSchedulers.IntfId,
1101 "OnuPortNo": trafficSchedulers.PortNo,
1102 }).Info("received RemoveTrafficSchedulers")
1103 if !s.enablePerf {
1104 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1105 if err != nil {
1106 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1107 return new(openolt.Empty), err
1108 }
1109 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1110 if err != nil {
1111 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1112 return new(openolt.Empty), err
1113 }
1114
1115 onu.TrafficSchedulers = nil
1116 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001117 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001118}
Scott Baker41724b82020-01-21 19:54:53 -08001119
1120// assumes caller has properly formulated an openolt.AlarmIndication
1121func (o OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
1122 msg := Message{
1123 Type: AlarmIndication,
1124 Data: ind,
1125 }
1126
1127 o.channel <- msg
1128 return nil
1129}