blob: 3c6c501a44b2e5a205eb955681f890791037d01f [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 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
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 Arya2225f202020-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 Arya2225f202020-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 Arya2225f202020-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 Arya2225f202020-01-29 18:05:01 +0530146 delay := time.Duration(olt.Delay * j) * time.Millisecond
147 o := CreateONU(&olt, *p, uint32(j+1), sTag, availableCTag, auth, dhcp, delay, isMock)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700148 p.Onus = append(p.Onus, o)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700149 availableCTag = availableCTag + 1
Matteo Scandolo4747d292019-08-05 11:50:18 -0700150 }
151
Pragya Arya6a708d62020-01-01 17:17:20 +0530152 olt.Pons = append(olt.Pons, p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700153 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100154
Matteo Scandolod32c3822019-11-26 15:57:46 -0700155 if isMock != true {
156 if err := olt.InternalState.Event("initialize"); err != nil {
157 log.Errorf("Error initializing OLT: %v", err)
158 return nil
159 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100160 }
161
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700162 return &olt
163}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700164
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100165func (o *OltDevice) InitOlt() error {
166
167 if oltServer == nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800168 oltServer, _ = o.newOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100169 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800170 // FIXME there should never be a server running if we are initializing the OLT
171 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100172 }
173
174 // create new channel for processOltMessages Go routine
175 o.channel = make(chan Message)
176
177 o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
178 // FIXME we are assuming we have only one NNI
179 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800180 // NOTE we want to make sure the state is down when we initialize the OLT,
181 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
182 // in-band management
183 o.Nnis[0].OperState.SetState("down")
184 ch, handle, err := o.Nnis[0].NewVethChan()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100185 if err == nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800186 oltLogger.WithFields(log.Fields{
187 "Type": o.Nnis[0].Type,
188 "IntfId": o.Nnis[0].ID,
189 "OperState": o.Nnis[0].OperState.Current(),
190 }).Info("NNI Channel created")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100191 o.nniPktInChannel = ch
Matteo Scandolo401503a2019-12-11 14:48:14 -0800192 o.nniHandle = handle
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100193 } else {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800194 oltLogger.Errorf("Error getting NNI channel: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100195 }
196 }
197
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100198 return nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700199}
200
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800201func (o *OltDevice) RestartOLT() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100202
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800203 rebootDelay := common.Options.Olt.OltRebootDelay
204
205 oltLogger.WithFields(log.Fields{
206 "oltId": o.ID,
207 }).Infof("Simulating OLT restart... (%ds)", rebootDelay)
208
209 // transition internal state to deleted
210 if err := o.InternalState.Event("delete"); err != nil {
211 oltLogger.WithFields(log.Fields{
212 "oltId": o.ID,
213 }).Errorf("Error deleting OLT: %v", err)
214 return err
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100215 }
216
217 // TODO handle hard poweroff (i.e. no indications sent to Voltha) vs soft poweroff
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800218 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
219 if err := o.StopOltServer(); err != nil {
Pragya Arya2225f202020-01-29 18:05:01 +0530220 oltLogger.Errorf("Error in stopping OLT server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100221 return err
222 }
223
Pragya Arya2225f202020-01-29 18:05:01 +0530224 for _, pon := range olt.Pons {
225 msg := Message{
226 Type: PonIndication,
227 Data: PonIndicationMessage{
228 OperState: DOWN,
229 PonPortID: pon.ID,
230 },
231 }
232 o.channel <- msg
233
234 for _, onu := range pon.Onus {
235 if onu.InternalState.Current() != "initialized" {
236 onu.InternalState.Event("disable")
237 }
238 }
239 }
240
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100241 // terminate the OLT's processOltMessages go routine
242 close(o.channel)
243 // terminate the OLT's processNniPacketIns go routine
Andy Bavier421f4d52020-01-21 15:39:22 -0700244 go o.nniHandle.Close()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100245 close(o.nniPktInChannel)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100246
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100247 time.Sleep(time.Duration(rebootDelay) * time.Second)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100248
249 if err := o.InternalState.Event("initialize"); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800250 oltLogger.WithFields(log.Fields{
251 "oltId": o.ID,
252 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100253 return err
254 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800255 oltLogger.WithFields(log.Fields{
256 "oltId": o.ID,
257 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100258 return nil
259}
260
261// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800262func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100263 address := common.Options.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700264 lis, err := net.Listen("tcp", address)
265 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700266 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700267 }
268 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100269
Matteo Scandolo4747d292019-08-05 11:50:18 -0700270 openolt.RegisterOpenoltServer(grpcServer, o)
271
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100272 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700273
Matteo Scandolo4747d292019-08-05 11:50:18 -0700274 go grpcServer.Serve(lis)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100275 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700276
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100277 return grpcServer, nil
278}
279
280// StopOltServer stops the OpenOLT grpc server
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800281func (o *OltDevice) StopOltServer() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100282 // TODO handle poweroff vs graceful shutdown
283 if oltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800284 oltLogger.WithFields(log.Fields{
285 "oltId": o.SerialNumber,
286 }).Warnf("Stopping OLT gRPC server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100287 oltServer.Stop()
288 oltServer = nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700289 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800290
Matteo Scandolo4747d292019-08-05 11:50:18 -0700291 return nil
292}
293
294// Device Methods
295
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100296// Enable implements the OpenOLT EnableIndicationServer functionality
297func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700298 oltLogger.Debug("Enable OLT called")
Pragya Arya2225f202020-01-29 18:05:01 +0530299 rebootFlag := false
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700300
David Bainbridge103cf022019-12-16 20:11:35 +0000301 // If enabled has already been called then an enabled context has
302 // been created. If this is the case then we want to cancel all the
303 // proessing loops associated with that enable before we recreate
304 // new ones
305 o.Lock()
306 if o.enableContext != nil && o.enableContextCancel != nil {
307 o.enableContextCancel()
Pragya Arya2225f202020-01-29 18:05:01 +0530308 rebootFlag = true
David Bainbridge103cf022019-12-16 20:11:35 +0000309 }
310 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
311 o.Unlock()
312
Matteo Scandolo4747d292019-08-05 11:50:18 -0700313 wg := sync.WaitGroup{}
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800314 wg.Add(3)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700315
Pragya Arya1cbefa42020-01-13 12:15:29 +0530316 o.OpenoltStream = &stream
317
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100318 // create Go routine to process all OLT events
David Bainbridge103cf022019-12-16 20:11:35 +0000319 go o.processOltMessages(o.enableContext, stream, &wg)
320 go o.processNniPacketIns(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700321
322 // enable the OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100323 oltMsg := Message{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700324 Type: OltIndication,
325 Data: OltIndicationMessage{
326 OperState: UP,
327 },
328 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100329 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700330
331 // send NNI Port Indications
332 for _, nni := range o.Nnis {
333 msg := Message{
334 Type: NniIndication,
335 Data: NniIndicationMessage{
336 OperState: UP,
337 NniPortID: nni.ID,
338 },
339 }
340 o.channel <- msg
341 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100342
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800343 go o.processOmciMessages(o.enableContext, stream, &wg)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100344
Pragya Arya2225f202020-01-29 18:05:01 +0530345 if rebootFlag == true {
346 for _, pon := range o.Pons {
347 if pon.InternalState.Current() == "disabled" {
348 msg := Message{
349 Type: PonIndication,
350 Data: PonIndicationMessage{
351 OperState: UP,
352 PonPortID: pon.ID,
353 },
354 }
355 o.channel <- msg
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000356 }
Pragya Arya2225f202020-01-29 18:05:01 +0530357 }
358 } else {
359
360 // 1. controlledActivation == Default: Send both PON and ONUs indications
361 // 2. controlledActivation == only-onu: that means only ONUs will be controlled activated, so auto send PON indications
362
363 if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
364 // send PON Port indications
365 for _, pon := range o.Pons {
366 msg := Message{
367 Type: PonIndication,
368 Data: PonIndicationMessage{
369 OperState: UP,
370 PonPortID: pon.ID,
371 },
372 }
373 o.channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700374 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700375 }
376 }
377
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800378 oltLogger.Debug("Enable OLT Done")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700379 wg.Wait()
380 return nil
381}
382
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800383func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400384 ch := omcisim.GetChannel()
385
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100386 oltLogger.Debug("Starting OMCI Indication Channel")
William Kurkian9dadc5b2019-10-22 13:51:57 -0400387
David Bainbridge103cf022019-12-16 20:11:35 +0000388loop:
389 for {
390 select {
391 case <-ctx.Done():
392 oltLogger.Debug("OMCI processing canceled via context")
393 break loop
394 case message, ok := <-ch:
395 if !ok || ctx.Err() != nil {
396 oltLogger.Debug("OMCI processing canceled via channel close")
397 break loop
398 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800399
400 oltLogger.WithFields(log.Fields{
401 "messageType": message.Type,
402 "OnuId": message.Data.OnuId,
403 "IntfId": message.Data.IntfId,
404 }).Info("Received message on OMCI Sim channel")
405
David Bainbridge103cf022019-12-16 20:11:35 +0000406 onuId := message.Data.OnuId
407 intfId := message.Data.IntfId
408 onu, err := o.FindOnuById(intfId, onuId)
409 if err != nil {
410 oltLogger.Errorf("Failed to find onu: %v", err)
411 continue
412 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800413 go onu.processOmciMessage(message, stream)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400414 }
William Kurkian9dadc5b2019-10-22 13:51:57 -0400415 }
David Bainbridge103cf022019-12-16 20:11:35 +0000416
417 wg.Done()
William Kurkian9dadc5b2019-10-22 13:51:57 -0400418}
419
Matteo Scandolo4747d292019-08-05 11:50:18 -0700420// Helpers method
421
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700422func (o OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700423 for _, pon := range o.Pons {
424 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700425 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700426 }
427 }
428 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
429}
430
431func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
432 for _, nni := range o.Nnis {
433 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700434 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700435 }
436 }
437 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
438}
439
Scott Baker41724b82020-01-21 19:54:53 -0800440func (o *OltDevice) sendAlarmIndication(alarmInd *openolt.AlarmIndication, stream openolt.Openolt_EnableIndicationServer) {
441 data := &openolt.Indication_AlarmInd{AlarmInd: alarmInd}
442 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
443 oltLogger.Errorf("Failed to send Alarm Indication: %v", err)
444 return
445 }
446
447 oltLogger.WithFields(log.Fields{
448 "AlarmIndication": alarmInd,
449 }).Debug("Sent Indication_AlarmInd")
450}
451
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100452func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700453 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
454 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700455 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800456 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700457 }
458
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700459 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700460 "OperState": msg.OperState,
461 }).Debug("Sent Indication_OltInd")
462}
463
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100464func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700465 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800466 if msg.OperState == UP {
467 if err := nni.OperState.Event("enable"); err != nil {
468 log.WithFields(log.Fields{
469 "Type": nni.Type,
470 "IntfId": nni.ID,
471 "OperState": nni.OperState.Current(),
472 }).Errorf("Can't move NNI Port to enabled state: %v", err)
473 }
474 } else if msg.OperState == DOWN {
475 if err := nni.OperState.Event("disable"); err != nil {
476 log.WithFields(log.Fields{
477 "Type": nni.Type,
478 "IntfId": nni.ID,
479 "OperState": nni.OperState.Current(),
480 }).Errorf("Can't move NNI Port to disable state: %v", err)
481 }
482 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700483 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700484 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700485 Type: nni.Type,
486 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700487 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700488 }}
489
490 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700491 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800492 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700493 }
494
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700495 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700496 "Type": nni.Type,
497 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700498 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700499 }).Debug("Sent Indication_IntfOperInd for NNI")
500}
501
Pragya Arya2225f202020-01-29 18:05:01 +0530502func (o *OltDevice) sendPonIndication(ponPortID uint32) {
503
504 stream := *o.OpenoltStream
505 pon, _ := o.GetPonById(ponPortID)
506 // Send IntfIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700507 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700508 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700509 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700510 }}
511
512 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700513 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800514 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700515 }
516
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700517 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700518 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700519 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700520 }).Debug("Sent Indication_IntfInd")
521
Pragya Arya2225f202020-01-29 18:05:01 +0530522 // Send IntfOperIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700523 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700524 Type: pon.Type,
525 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700526 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700527 }}
528
529 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700530 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800531 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700532 }
533
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700534 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700535 "Type": pon.Type,
536 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700537 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700538 }).Debug("Sent Indication_IntfOperInd for PON")
539}
540
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100541// processOltMessages handles messages received over the OpenOLT interface
David Bainbridge103cf022019-12-16 20:11:35 +0000542func (o *OltDevice) processOltMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100543 oltLogger.Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000544 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700545
David Bainbridge103cf022019-12-16 20:11:35 +0000546loop:
547 for {
548 select {
549 case <-ctx.Done():
550 oltLogger.Debug("OLT Indication processing canceled via context")
551 break loop
552 case message, ok := <-ch:
553 if !ok || ctx.Err() != nil {
554 oltLogger.Debug("OLT Indication processing canceled via closed channel")
555 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700556 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700557
David Bainbridge103cf022019-12-16 20:11:35 +0000558 oltLogger.WithFields(log.Fields{
559 "oltId": o.ID,
560 "messageType": message.Type,
561 }).Trace("Received message")
562
563 switch message.Type {
564 case OltIndication:
565 msg, _ := message.Data.(OltIndicationMessage)
566 if msg.OperState == UP {
567 o.InternalState.Event("enable")
568 o.OperState.Event("enable")
569 } else if msg.OperState == DOWN {
570 o.InternalState.Event("disable")
571 o.OperState.Event("disable")
572 }
573 o.sendOltIndication(msg, stream)
Scott Baker41724b82020-01-21 19:54:53 -0800574 case AlarmIndication:
575 alarmInd, _ := message.Data.(*openolt.AlarmIndication)
576 o.sendAlarmIndication(alarmInd, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000577 case NniIndication:
578 msg, _ := message.Data.(NniIndicationMessage)
579 o.sendNniIndication(msg, stream)
580 case PonIndication:
581 msg, _ := message.Data.(PonIndicationMessage)
Pragya Arya2225f202020-01-29 18:05:01 +0530582 pon, _ := o.GetPonById(msg.PonPortID)
583 if msg.OperState == UP {
584 pon.OperState.Event("enable")
585 pon.InternalState.Event("enable")
586 } else if msg.OperState == DOWN {
587 pon.OperState.Event("disable")
588 pon.InternalState.Event("disable")
589 }
David Bainbridge103cf022019-12-16 20:11:35 +0000590 default:
591 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
592 }
593 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700594 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100595 wg.Done()
596 oltLogger.Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700597}
598
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100599// processNniPacketIns handles messages received over the NNI interface
David Bainbridge103cf022019-12-16 20:11:35 +0000600func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700601 oltLogger.WithFields(log.Fields{
602 "nniChannel": o.nniPktInChannel,
Matteo Scandolo401503a2019-12-11 14:48:14 -0800603 }).Debug("Started Processing Packets arriving from the NNI")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700604 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700605
David Bainbridge103cf022019-12-16 20:11:35 +0000606 ch := o.nniPktInChannel
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700607
David Bainbridge103cf022019-12-16 20:11:35 +0000608loop:
609 for {
610 select {
611 case <-ctx.Done():
612 oltLogger.Debug("NNI Indication processing canceled via context")
613 break loop
614 case message, ok := <-ch:
615 if !ok || ctx.Err() != nil {
616 oltLogger.Debug("NNI Indication processing canceled via channel closed")
617 break loop
618 }
619 oltLogger.Tracef("Received packets on NNI Channel")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700620
David Bainbridge103cf022019-12-16 20:11:35 +0000621 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700622
David Bainbridge103cf022019-12-16 20:11:35 +0000623 if err != nil {
624 log.WithFields(log.Fields{
625 "IntfType": "nni",
626 "IntfId": nniId,
627 "Pkt": message.Pkt.Data(),
628 }).Error("Can't find Dst MacAddress in packet")
629 return
630 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700631
David Bainbridge103cf022019-12-16 20:11:35 +0000632 onu, err := o.FindOnuByMacAddress(onuMac)
633 if err != nil {
634 log.WithFields(log.Fields{
635 "IntfType": "nni",
636 "IntfId": nniId,
637 "Pkt": message.Pkt.Data(),
638 "MacAddress": onuMac.String(),
639 }).Error("Can't find ONU with MacAddress")
640 return
641 }
642
643 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
644 if err != nil {
645 log.Error("Fail to add double tag to packet")
646 }
647
648 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
649 IntfType: "nni",
650 IntfId: nniId,
651 Pkt: doubleTaggedPkt.Data()}}
652 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
653 oltLogger.WithFields(log.Fields{
654 "IntfType": data.PktInd.IntfType,
655 "IntfId": nniId,
656 "Pkt": doubleTaggedPkt.Data(),
657 }).Errorf("Fail to send PktInd indication: %v", err)
658 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700659 oltLogger.WithFields(log.Fields{
660 "IntfType": data.PktInd.IntfType,
661 "IntfId": nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700662 "Pkt": doubleTaggedPkt.Data(),
David Bainbridge103cf022019-12-16 20:11:35 +0000663 "OnuSn": onu.Sn(),
664 }).Tracef("Sent PktInd indication")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700665 }
666 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100667 wg.Done()
668 oltLogger.WithFields(log.Fields{
669 "nniChannel": o.nniPktInChannel,
670 }).Warn("Stopped handling NNI Channel")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700671}
672
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700673// returns an ONU with a given Serial Number
674func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200675 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700676 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700677 for _, pon := range o.Pons {
678 for _, onu := range pon.Onus {
679 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700680 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700681 }
682 }
683 }
684
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700685 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-serial-number-%s", serialNumber))
686}
687
William Kurkian9dadc5b2019-10-22 13:51:57 -0400688// returns an ONU with a given interface/Onu Id
689func (o OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200690 // TODO this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400691 // memoizing it will remove the bottleneck
692 for _, pon := range o.Pons {
693 if pon.ID == intfId {
694 for _, onu := range pon.Onus {
695 if onu.ID == onuId {
696 return onu, nil
697 }
698 }
699 }
700 }
701 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-id-%v-%v", intfId, onuId))
702}
703
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700704// returns an ONU with a given Mac Address
705func (o OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200706 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700707 // memoizing it will remove the bottleneck
708 for _, pon := range o.Pons {
709 for _, onu := range pon.Onus {
710 if onu.HwAddress.String() == mac.String() {
Matteo Scandolo27428702019-10-11 16:21:16 -0700711 return onu, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700712 }
713 }
714 }
715
716 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-mac-address-%s", mac))
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700717}
718
Matteo Scandolo4747d292019-08-05 11:50:18 -0700719// GRPC Endpoints
720
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700721func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700722 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700723 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700724 }).Info("Received ActivateOnu call from VOLTHA")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700725
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700726 pon, _ := o.GetPonById(onu.IntfId)
727 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
William Kurkian0418bc82019-11-06 12:16:24 -0500728 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700729
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700730 if err := _onu.OperState.Event("enable"); err != nil {
731 oltLogger.WithFields(log.Fields{
732 "IntfId": _onu.PonPortID,
733 "OnuSn": _onu.Sn(),
734 "OnuId": _onu.ID,
735 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700736 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700737 if err := _onu.InternalState.Event("enable"); err != nil {
738 oltLogger.WithFields(log.Fields{
739 "IntfId": _onu.PonPortID,
740 "OnuSn": _onu.Sn(),
741 "OnuId": _onu.ID,
742 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
743 }
744
745 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
746
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700747 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700748}
749
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700750func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700751 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700752 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700753}
754
Pragya Arya1cbefa42020-01-13 12:15:29 +0530755func (o OltDevice) DeleteOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
756 oltLogger.WithFields(log.Fields{
757 "IntfId": onu.IntfId,
758 "OnuId": onu.OnuId,
759 }).Info("Received DeleteOnu call from VOLTHA")
760
761 pon, err := o.GetPonById(onu.IntfId)
762 if err != nil {
763 oltLogger.WithFields(log.Fields{
764 "OnuId": onu.OnuId,
765 "IntfId": onu.IntfId,
766 "err": err,
767 }).Error("Can't find PonPort")
768 }
769 _onu, err := pon.GetOnuById(onu.OnuId)
770 if err != nil {
771 oltLogger.WithFields(log.Fields{
772 "OnuId": onu.OnuId,
773 "IntfId": onu.IntfId,
774 "err": err,
775 }).Error("Can't find Onu")
776 }
777
778 if err := _onu.InternalState.Event("initialize"); err != nil {
779 oltLogger.WithFields(log.Fields{
780 "IntfId": _onu.PonPortID,
781 "OnuSn": _onu.Sn(),
782 "OnuId": _onu.ID,
783 }).Infof("Failed to transition ONU to initialized state: %s", err.Error())
784 }
785
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700786 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700787}
788
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700789func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700790 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800791 oltLogger.WithFields(log.Fields{
792 "oltId": o.ID,
793 }).Info("Disabling OLT")
794
Matteo Scandolo401503a2019-12-11 14:48:14 -0800795 for _, pon := range o.Pons {
Pragya Arya2225f202020-01-29 18:05:01 +0530796 if pon.InternalState.Current() == "enabled" {
797 // disable PONs
798 msg := Message{
799 Type: PonIndication,
800 Data: PonIndicationMessage{
801 OperState: DOWN,
802 PonPortID: pon.ID,
803 },
804 }
805 o.channel <- msg
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800806 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800807 }
808
Matteo Scandolo401503a2019-12-11 14:48:14 -0800809 // Note that we are not disabling the NNI as the real OLT does not.
810 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800811
812 // disable OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100813 oltMsg := Message{
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700814 Type: OltIndication,
815 Data: OltIndicationMessage{
816 OperState: DOWN,
817 },
818 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100819 o.channel <- oltMsg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700820 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700821}
822
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700823func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700824 oltLogger.Error("DisablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700825 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700826}
827
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100828func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700829 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700830 o.Enable(stream)
831 return nil
832}
833
Pragya Arya2225f202020-01-29 18:05:01 +0530834func (o OltDevice) EnablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
835 oltLogger.Errorf("EnablePonIf request received for PON %d", intf.IntfId)
836 ponID := intf.GetIntfId()
837 msg := Message{
838 Type: PonIndication,
839 Data: PonIndicationMessage{
840 OperState: UP,
841 PonPortID: ponID,
842 },
843 }
844 o.channel <- msg
845
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700846 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700847}
848
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700849func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700850 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700851 "IntfId": flow.AccessIntfId,
852 "OnuId": flow.OnuId,
853 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700854 "InnerVlan": flow.Classifier.IVid,
855 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700856 "FlowType": flow.FlowType,
857 "FlowId": flow.FlowId,
858 "UniID": flow.UniId,
859 "PortNo": flow.PortNo,
860 }).Tracef("OLT receives Flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700861 // TODO optionally store flows somewhere
862
863 if flow.AccessIntfId == -1 {
864 oltLogger.WithFields(log.Fields{
865 "FlowId": flow.FlowId,
866 }).Debugf("This is an OLT flow")
867 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700868 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700869 if err != nil {
870 oltLogger.WithFields(log.Fields{
871 "OnuId": flow.OnuId,
872 "IntfId": flow.AccessIntfId,
873 "err": err,
874 }).Error("Can't find PonPort")
875 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700876 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700877 if err != nil {
878 oltLogger.WithFields(log.Fields{
879 "OnuId": flow.OnuId,
880 "IntfId": flow.AccessIntfId,
881 "err": err,
882 }).Error("Can't find Onu")
883 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700884
885 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700886 Type: FlowUpdate,
887 Data: OnuFlowUpdateMessage{
888 PonPortID: pon.ID,
889 OnuID: onu.ID,
890 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700891 },
892 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700893 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700894 }
895
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700896 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700897}
898
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700899func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
900 oltLogger.Tracef("received FlowRemove")
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700901 // TODO store flows somewhere
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700902 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700903}
904
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700905func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo18859852020-01-15 13:33:57 -0800906 res := openolt.Heartbeat{HeartbeatSignature: uint32(time.Now().Unix())}
907 oltLogger.WithFields(log.Fields{
908 "signature": res.HeartbeatSignature,
909 }).Trace("HeartbeatCheck")
910 return &res, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700911}
912
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700913func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700914
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700915 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700916 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700917 "PonPorts": o.NumPon,
918 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700919 devinfo := new(openolt.DeviceInfo)
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100920 devinfo.Vendor = common.Options.Olt.Vendor
921 devinfo.Model = common.Options.Olt.Model
922 devinfo.HardwareVersion = common.Options.Olt.HardwareVersion
923 devinfo.FirmwareVersion = common.Options.Olt.FirmwareVersion
924 devinfo.Technology = common.Options.Olt.Technology
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700925 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700926 devinfo.OnuIdStart = 1
927 devinfo.OnuIdEnd = 255
928 devinfo.AllocIdStart = 1024
929 devinfo.AllocIdEnd = 16383
930 devinfo.GemportIdStart = 1024
931 devinfo.GemportIdEnd = 65535
932 devinfo.FlowIdStart = 1
933 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -0700934 devinfo.DeviceSerialNumber = o.SerialNumber
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100935 devinfo.DeviceId = common.Options.Olt.DeviceId
Matteo Scandolo4747d292019-08-05 11:50:18 -0700936
937 return devinfo, nil
938}
939
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700940func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700941 pon, _ := o.GetPonById(omci_msg.IntfId)
942 onu, _ := pon.GetOnuById(omci_msg.OnuId)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700943 oltLogger.WithFields(log.Fields{
944 "IntfId": onu.PonPortID,
945 "OnuId": onu.ID,
946 "OnuSn": onu.Sn(),
947 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700948 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700949 Type: OMCI,
950 Data: OmciMessage{
951 OnuSN: onu.SerialNumber,
952 OnuID: onu.ID,
953 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700954 },
955 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700956 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700957 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700958}
959
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700960func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700961 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700962 if err != nil {
963 oltLogger.WithFields(log.Fields{
964 "OnuId": onuPkt.OnuId,
965 "IntfId": onuPkt.IntfId,
966 "err": err,
967 }).Error("Can't find PonPort")
968 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700969 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700970 if err != nil {
971 oltLogger.WithFields(log.Fields{
972 "OnuId": onuPkt.OnuId,
973 "IntfId": onuPkt.IntfId,
974 "err": err,
975 }).Error("Can't find Onu")
976 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700977
Matteo Scandolo075b1892019-10-07 12:11:07 -0700978 oltLogger.WithFields(log.Fields{
979 "IntfId": onu.PonPortID,
980 "OnuId": onu.ID,
981 "OnuSn": onu.Sn(),
982 }).Tracef("Received OnuPacketOut")
983
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700984 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700985 pktType, err := packetHandlers.IsEapolOrDhcp(rawpkt)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700986
Matteo Scandolo075b1892019-10-07 12:11:07 -0700987 msg := Message{
988 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700989 Data: OnuPacketMessage{
Matteo Scandolo075b1892019-10-07 12:11:07 -0700990 IntfId: onuPkt.IntfId,
991 OnuId: onuPkt.OnuId,
992 Packet: rawpkt,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700993 Type: pktType,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700994 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700995 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700996 onu.Channel <- msg
997
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700998 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700999}
1000
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001001func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolod02b79b2019-12-05 16:42:13 -08001002 oltLogger.WithFields(log.Fields{
1003 "oltId": o.ID,
1004 }).Info("Shutting down")
1005 go o.RestartOLT()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001006 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001007}
1008
1009func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Pragya Arya6a708d62020-01-01 17:17:20 +05301010 oltLogger.WithFields(log.Fields{
1011 "oltId": o.ID,
1012 }).Info("Received ReenableOlt request from VOLTHA")
1013
Pragya Arya2225f202020-01-29 18:05:01 +05301014 // enable OLT
1015 oltMsg := Message{
1016 Type: OltIndication,
1017 Data: OltIndicationMessage{
1018 OperState: UP,
1019 },
Pragya Arya1881df02020-01-29 18:05:01 +05301020 }
Pragya Arya2225f202020-01-29 18:05:01 +05301021 o.channel <- oltMsg
Pragya Arya6a708d62020-01-01 17:17:20 +05301022
Pragya Arya2225f202020-01-29 18:05:01 +05301023 for _, pon := range o.Pons {
1024 if pon.InternalState.Current() == "disabled" {
1025 msg := Message{
1026 Type: PonIndication,
1027 Data: PonIndicationMessage{
1028 OperState: UP,
1029 PonPortID: pon.ID,
1030 },
1031 }
1032 o.channel <- msg
1033 }
1034 }
Matteo Scandoloe60a5052020-02-07 00:31:14 +00001035
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001036 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001037}
1038
1039func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001040 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
1041
Zdravko Bozakov681364d2019-11-10 14:28:46 +01001042 o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001043 // NOTE should we return an error if sendNniPakcet fails?
1044 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001045}
1046
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001047func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001048 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001049 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001050}
1051
Matteo Scandolo4747d292019-08-05 11:50:18 -07001052func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001053 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001054 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001055}
1056
1057func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001058 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001059 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -07001060}
1061
1062func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001063 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001064 return new(openolt.Empty), nil
1065}
1066
1067func (s OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001068 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001069 return new(openolt.Empty), nil
1070}
1071
1072func (s OltDevice) CreateTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001073 oltLogger.Info("received CreateTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001074 return new(openolt.Empty), nil
1075}
1076
1077func (s OltDevice) RemoveTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001078 oltLogger.Info("received RemoveTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001079 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001080}
Scott Baker41724b82020-01-21 19:54:53 -08001081
1082// assumes caller has properly formulated an openolt.AlarmIndication
1083func (o OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
1084 msg := Message{
1085 Type: AlarmIndication,
1086 Data: ind,
1087 }
1088
1089 o.channel <- msg
1090 return nil
1091}