blob: d5ba84f321716f75467150074639a384ccfca4df [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"
Pragya Arya8bdb4532020-03-02 17:08:09 +053039 "google.golang.org/grpc/codes"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010040 "google.golang.org/grpc/reflection"
Pragya Arya8bdb4532020-03-02 17:08:09 +053041 "google.golang.org/grpc/status"
Matteo Scandolo4747d292019-08-05 11:50:18 -070042)
43
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070044var oltLogger = log.WithFields(log.Fields{
Matteo Scandolo84f7d482019-08-08 19:00:47 -070045 "module": "OLT",
46})
47
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070048type OltDevice struct {
David Bainbridge103cf022019-12-16 20:11:35 +000049 sync.Mutex
50
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070051 // BBSIM Internals
Pragya Arya2225f202020-01-29 18:05:01 +053052 ID int
53 SerialNumber string
54 NumNni int
55 NumPon int
56 NumOnuPerPon int
57 InternalState *fsm.FSM
58 channel chan Message
59 nniPktInChannel chan *bbsim.PacketMsg // packets coming in from the NNI and going to VOLTHA
60 nniHandle *pcap.Handle // handle on the NNI interface, close it when shutting down the NNI channel
Pragya Arya8bdb4532020-03-02 17:08:09 +053061 Flows map[FlowKey]openolt.Flow
Pragya Arya2225f202020-01-29 18:05:01 +053062 Delay int
63 ControlledActivation mode
Matteo Scandoloe33447a2019-10-31 12:38:23 -070064
Matteo Scandolo27428702019-10-11 16:21:16 -070065 Pons []*PonPort
66 Nnis []*NniPort
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070067
68 // OLT Attributes
69 OperState *fsm.FSM
David Bainbridge103cf022019-12-16 20:11:35 +000070
71 enableContext context.Context
72 enableContextCancel context.CancelFunc
Pragya Arya1cbefa42020-01-13 12:15:29 +053073
74 OpenoltStream *openolt.Openolt_EnableIndicationServer
Anand S Katti09541352020-01-29 15:54:01 +053075 enablePerf bool
Matteo Scandolo4747d292019-08-05 11:50:18 -070076}
77
Matteo Scandolo27428702019-10-11 16:21:16 -070078var olt OltDevice
Zdravko Bozakov681364d2019-11-10 14:28:46 +010079var oltServer *grpc.Server
Matteo Scandolo84f7d482019-08-08 19:00:47 -070080
Matteo Scandolo27428702019-10-11 16:21:16 -070081func GetOLT() *OltDevice {
82 return &olt
Matteo Scandolo84f7d482019-08-08 19:00:47 -070083}
84
Anand S Katti09541352020-01-29 15:54:01 +053085func 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 -070086 oltLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070087 "ID": oltId,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070088 "NumNni": nni,
89 "NumPon": pon,
90 "NumOnuPerPon": onuPerPon,
Matteo Scandolo4747d292019-08-05 11:50:18 -070091 }).Debug("CreateOLT")
92
Matteo Scandolo84f7d482019-08-08 19:00:47 -070093 olt = OltDevice{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070094 ID: oltId,
95 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", oltId),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070096 OperState: getOperStateFSM(func(e *fsm.Event) {
97 oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
98 }),
Zdravko Bozakov681364d2019-11-10 14:28:46 +010099 NumNni: nni,
100 NumPon: pon,
101 NumOnuPerPon: onuPerPon,
102 Pons: []*PonPort{},
103 Nnis: []*NniPort{},
104 Delay: delay,
Pragya Arya8bdb4532020-03-02 17:08:09 +0530105 Flows: make(map[FlowKey]openolt.Flow),
Anand S Katti09541352020-01-29 15:54:01 +0530106 enablePerf: enablePerf,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700107 }
108
Pragya Arya2225f202020-01-29 18:05:01 +0530109 if val, ok := ControlledActivationModes[ca]; ok {
110 olt.ControlledActivation = val
111 } else {
112 oltLogger.Warn("Unknown ControlledActivation Mode given, running in Default mode")
113 olt.ControlledActivation = Default
114 }
115
Matteo Scandolo4747d292019-08-05 11:50:18 -0700116 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700117 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700118 olt.InternalState = fsm.NewFSM(
119 "created",
120 fsm.Events{
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800121 {Name: "initialize", Src: []string{"created", "deleted"}, Dst: "initialized"},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100122 {Name: "enable", Src: []string{"initialized", "disabled"}, Dst: "enabled"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700123 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
Mahir Gunyel6dad4452020-01-06 12:59:04 -0800124 //delete event in enabled state below is for reboot OLT case.
125 {Name: "delete", Src: []string{"disabled", "enabled"}, Dst: "deleted"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700126 },
127 fsm.Callbacks{
128 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700129 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700130 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100131 "enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
Matteo Scandolo4747d292019-08-05 11:50:18 -0700132 },
133 )
134
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700135 if isMock != true {
136 // create NNI Port
137 nniPort, err := CreateNNI(&olt)
138 if err != nil {
139 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
140 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700141
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700142 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700143 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700144
Matteo Scandolo4747d292019-08-05 11:50:18 -0700145 // create PON ports
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700146 availableCTag := cTagInit
Matteo Scandolo4747d292019-08-05 11:50:18 -0700147 for i := 0; i < pon; i++ {
Pragya Arya2225f202020-01-29 18:05:01 +0530148 p := CreatePonPort(&olt, uint32(i))
Matteo Scandolo4747d292019-08-05 11:50:18 -0700149
150 // create ONU devices
151 for j := 0; j < onuPerPon; j++ {
Matteo Scandolo583f17d2020-02-13 10:35:17 -0800152 delay := time.Duration(olt.Delay*j) * time.Millisecond
Pragya Arya2225f202020-01-29 18:05:01 +0530153 o := CreateONU(&olt, *p, uint32(j+1), sTag, availableCTag, auth, dhcp, delay, isMock)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700154 p.Onus = append(p.Onus, o)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700155 availableCTag = availableCTag + 1
Matteo Scandolo4747d292019-08-05 11:50:18 -0700156 }
157
Pragya Arya6a708d62020-01-01 17:17:20 +0530158 olt.Pons = append(olt.Pons, p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700159 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100160
Matteo Scandolod32c3822019-11-26 15:57:46 -0700161 if isMock != true {
162 if err := olt.InternalState.Event("initialize"); err != nil {
163 log.Errorf("Error initializing OLT: %v", err)
164 return nil
165 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100166 }
167
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700168 return &olt
169}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700170
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100171func (o *OltDevice) InitOlt() error {
172
173 if oltServer == nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800174 oltServer, _ = o.newOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100175 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800176 // FIXME there should never be a server running if we are initializing the OLT
177 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100178 }
179
180 // create new channel for processOltMessages Go routine
181 o.channel = make(chan Message)
182
183 o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
184 // FIXME we are assuming we have only one NNI
185 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800186 // NOTE we want to make sure the state is down when we initialize the OLT,
187 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
188 // in-band management
189 o.Nnis[0].OperState.SetState("down")
190 ch, handle, err := o.Nnis[0].NewVethChan()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100191 if err == nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800192 oltLogger.WithFields(log.Fields{
193 "Type": o.Nnis[0].Type,
194 "IntfId": o.Nnis[0].ID,
195 "OperState": o.Nnis[0].OperState.Current(),
196 }).Info("NNI Channel created")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100197 o.nniPktInChannel = ch
Matteo Scandolo401503a2019-12-11 14:48:14 -0800198 o.nniHandle = handle
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100199 } else {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800200 oltLogger.Errorf("Error getting NNI channel: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100201 }
202 }
203
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100204 return nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700205}
206
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800207func (o *OltDevice) RestartOLT() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100208
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800209 rebootDelay := common.Options.Olt.OltRebootDelay
210
211 oltLogger.WithFields(log.Fields{
212 "oltId": o.ID,
213 }).Infof("Simulating OLT restart... (%ds)", rebootDelay)
214
215 // transition internal state to deleted
216 if err := o.InternalState.Event("delete"); err != nil {
217 oltLogger.WithFields(log.Fields{
218 "oltId": o.ID,
219 }).Errorf("Error deleting OLT: %v", err)
220 return err
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100221 }
222
223 // TODO handle hard poweroff (i.e. no indications sent to Voltha) vs soft poweroff
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800224 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
225 if err := o.StopOltServer(); err != nil {
Pragya Arya2225f202020-01-29 18:05:01 +0530226 oltLogger.Errorf("Error in stopping OLT server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100227 return err
228 }
229
Pragya Arya2225f202020-01-29 18:05:01 +0530230 for _, pon := range olt.Pons {
231 msg := Message{
232 Type: PonIndication,
233 Data: PonIndicationMessage{
234 OperState: DOWN,
235 PonPortID: pon.ID,
236 },
237 }
238 o.channel <- msg
239
240 for _, onu := range pon.Onus {
241 if onu.InternalState.Current() != "initialized" {
242 onu.InternalState.Event("disable")
243 }
244 }
245 }
246
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100247 // terminate the OLT's processOltMessages go routine
248 close(o.channel)
249 // terminate the OLT's processNniPacketIns go routine
Andy Bavier421f4d52020-01-21 15:39:22 -0700250 go o.nniHandle.Close()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100251 close(o.nniPktInChannel)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100252
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100253 time.Sleep(time.Duration(rebootDelay) * time.Second)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100254
255 if err := o.InternalState.Event("initialize"); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800256 oltLogger.WithFields(log.Fields{
257 "oltId": o.ID,
258 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100259 return err
260 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800261 oltLogger.WithFields(log.Fields{
262 "oltId": o.ID,
263 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100264 return nil
265}
266
267// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800268func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100269 address := common.Options.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700270 lis, err := net.Listen("tcp", address)
271 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700272 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700273 }
274 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100275
Matteo Scandolo4747d292019-08-05 11:50:18 -0700276 openolt.RegisterOpenoltServer(grpcServer, o)
277
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100278 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700279
Matteo Scandolo4747d292019-08-05 11:50:18 -0700280 go grpcServer.Serve(lis)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100281 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700282
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100283 return grpcServer, nil
284}
285
286// StopOltServer stops the OpenOLT grpc server
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800287func (o *OltDevice) StopOltServer() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100288 // TODO handle poweroff vs graceful shutdown
289 if oltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800290 oltLogger.WithFields(log.Fields{
291 "oltId": o.SerialNumber,
292 }).Warnf("Stopping OLT gRPC server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100293 oltServer.Stop()
294 oltServer = nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700295 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800296
Matteo Scandolo4747d292019-08-05 11:50:18 -0700297 return nil
298}
299
300// Device Methods
301
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100302// Enable implements the OpenOLT EnableIndicationServer functionality
303func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700304 oltLogger.Debug("Enable OLT called")
Pragya Arya2225f202020-01-29 18:05:01 +0530305 rebootFlag := false
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700306
David Bainbridge103cf022019-12-16 20:11:35 +0000307 // If enabled has already been called then an enabled context has
308 // been created. If this is the case then we want to cancel all the
309 // proessing loops associated with that enable before we recreate
310 // new ones
311 o.Lock()
312 if o.enableContext != nil && o.enableContextCancel != nil {
313 o.enableContextCancel()
Pragya Arya2225f202020-01-29 18:05:01 +0530314 rebootFlag = true
David Bainbridge103cf022019-12-16 20:11:35 +0000315 }
316 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
317 o.Unlock()
318
Matteo Scandolo4747d292019-08-05 11:50:18 -0700319 wg := sync.WaitGroup{}
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800320 wg.Add(3)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700321
Pragya Arya1cbefa42020-01-13 12:15:29 +0530322 o.OpenoltStream = &stream
323
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100324 // create Go routine to process all OLT events
David Bainbridge103cf022019-12-16 20:11:35 +0000325 go o.processOltMessages(o.enableContext, stream, &wg)
326 go o.processNniPacketIns(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700327
328 // enable the OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100329 oltMsg := Message{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700330 Type: OltIndication,
331 Data: OltIndicationMessage{
332 OperState: UP,
333 },
334 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100335 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700336
337 // send NNI Port Indications
338 for _, nni := range o.Nnis {
339 msg := Message{
340 Type: NniIndication,
341 Data: NniIndicationMessage{
342 OperState: UP,
343 NniPortID: nni.ID,
344 },
345 }
346 o.channel <- msg
347 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100348
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800349 go o.processOmciMessages(o.enableContext, stream, &wg)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100350
Pragya Arya2225f202020-01-29 18:05:01 +0530351 if rebootFlag == true {
352 for _, pon := range o.Pons {
353 if pon.InternalState.Current() == "disabled" {
354 msg := Message{
355 Type: PonIndication,
356 Data: PonIndicationMessage{
357 OperState: UP,
358 PonPortID: pon.ID,
359 },
360 }
361 o.channel <- msg
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000362 }
Pragya Arya2225f202020-01-29 18:05:01 +0530363 }
364 } else {
365
366 // 1. controlledActivation == Default: Send both PON and ONUs indications
367 // 2. controlledActivation == only-onu: that means only ONUs will be controlled activated, so auto send PON indications
368
369 if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
370 // send PON Port indications
371 for _, pon := range o.Pons {
372 msg := Message{
373 Type: PonIndication,
374 Data: PonIndicationMessage{
375 OperState: UP,
376 PonPortID: pon.ID,
377 },
378 }
379 o.channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700380 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700381 }
382 }
383
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800384 oltLogger.Debug("Enable OLT Done")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700385 wg.Wait()
386 return nil
387}
388
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800389func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400390 ch := omcisim.GetChannel()
391
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100392 oltLogger.Debug("Starting OMCI Indication Channel")
William Kurkian9dadc5b2019-10-22 13:51:57 -0400393
David Bainbridge103cf022019-12-16 20:11:35 +0000394loop:
395 for {
396 select {
397 case <-ctx.Done():
398 oltLogger.Debug("OMCI processing canceled via context")
399 break loop
400 case message, ok := <-ch:
401 if !ok || ctx.Err() != nil {
402 oltLogger.Debug("OMCI processing canceled via channel close")
403 break loop
404 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800405
406 oltLogger.WithFields(log.Fields{
407 "messageType": message.Type,
408 "OnuId": message.Data.OnuId,
409 "IntfId": message.Data.IntfId,
410 }).Info("Received message on OMCI Sim channel")
411
David Bainbridge103cf022019-12-16 20:11:35 +0000412 onuId := message.Data.OnuId
413 intfId := message.Data.IntfId
414 onu, err := o.FindOnuById(intfId, onuId)
415 if err != nil {
416 oltLogger.Errorf("Failed to find onu: %v", err)
417 continue
418 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800419 go onu.processOmciMessage(message, stream)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400420 }
William Kurkian9dadc5b2019-10-22 13:51:57 -0400421 }
David Bainbridge103cf022019-12-16 20:11:35 +0000422
423 wg.Done()
William Kurkian9dadc5b2019-10-22 13:51:57 -0400424}
425
Matteo Scandolo4747d292019-08-05 11:50:18 -0700426// Helpers method
427
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700428func (o OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700429 for _, pon := range o.Pons {
430 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700431 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700432 }
433 }
434 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
435}
436
437func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
438 for _, nni := range o.Nnis {
439 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700440 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700441 }
442 }
443 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
444}
445
Scott Baker41724b82020-01-21 19:54:53 -0800446func (o *OltDevice) sendAlarmIndication(alarmInd *openolt.AlarmIndication, stream openolt.Openolt_EnableIndicationServer) {
447 data := &openolt.Indication_AlarmInd{AlarmInd: alarmInd}
448 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
449 oltLogger.Errorf("Failed to send Alarm Indication: %v", err)
450 return
451 }
452
453 oltLogger.WithFields(log.Fields{
454 "AlarmIndication": alarmInd,
455 }).Debug("Sent Indication_AlarmInd")
456}
457
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100458func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700459 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
460 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700461 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800462 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700463 }
464
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700465 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700466 "OperState": msg.OperState,
467 }).Debug("Sent Indication_OltInd")
468}
469
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100470func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700471 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800472 if msg.OperState == UP {
473 if err := nni.OperState.Event("enable"); err != nil {
474 log.WithFields(log.Fields{
475 "Type": nni.Type,
476 "IntfId": nni.ID,
477 "OperState": nni.OperState.Current(),
478 }).Errorf("Can't move NNI Port to enabled state: %v", err)
479 }
480 } else if msg.OperState == DOWN {
481 if err := nni.OperState.Event("disable"); err != nil {
482 log.WithFields(log.Fields{
483 "Type": nni.Type,
484 "IntfId": nni.ID,
485 "OperState": nni.OperState.Current(),
486 }).Errorf("Can't move NNI Port to disable state: %v", err)
487 }
488 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700489 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700490 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700491 Type: nni.Type,
492 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700493 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700494 }}
495
496 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700497 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800498 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700499 }
500
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700501 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700502 "Type": nni.Type,
503 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700504 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700505 }).Debug("Sent Indication_IntfOperInd for NNI")
506}
507
Pragya Arya2225f202020-01-29 18:05:01 +0530508func (o *OltDevice) sendPonIndication(ponPortID uint32) {
509
510 stream := *o.OpenoltStream
511 pon, _ := o.GetPonById(ponPortID)
512 // Send IntfIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700513 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700514 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700515 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700516 }}
517
518 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700519 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800520 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700521 }
522
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700523 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700524 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700525 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700526 }).Debug("Sent Indication_IntfInd")
527
Pragya Arya2225f202020-01-29 18:05:01 +0530528 // Send IntfOperIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700529 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700530 Type: pon.Type,
531 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700532 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700533 }}
534
535 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700536 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800537 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700538 }
539
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700540 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700541 "Type": pon.Type,
542 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700543 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700544 }).Debug("Sent Indication_IntfOperInd for PON")
545}
546
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100547// processOltMessages handles messages received over the OpenOLT interface
David Bainbridge103cf022019-12-16 20:11:35 +0000548func (o *OltDevice) processOltMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100549 oltLogger.Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000550 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700551
David Bainbridge103cf022019-12-16 20:11:35 +0000552loop:
553 for {
554 select {
555 case <-ctx.Done():
556 oltLogger.Debug("OLT Indication processing canceled via context")
557 break loop
558 case message, ok := <-ch:
559 if !ok || ctx.Err() != nil {
560 oltLogger.Debug("OLT Indication processing canceled via closed channel")
561 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700562 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700563
David Bainbridge103cf022019-12-16 20:11:35 +0000564 oltLogger.WithFields(log.Fields{
565 "oltId": o.ID,
566 "messageType": message.Type,
567 }).Trace("Received message")
568
569 switch message.Type {
570 case OltIndication:
571 msg, _ := message.Data.(OltIndicationMessage)
572 if msg.OperState == UP {
573 o.InternalState.Event("enable")
574 o.OperState.Event("enable")
575 } else if msg.OperState == DOWN {
576 o.InternalState.Event("disable")
577 o.OperState.Event("disable")
578 }
579 o.sendOltIndication(msg, stream)
Scott Baker41724b82020-01-21 19:54:53 -0800580 case AlarmIndication:
581 alarmInd, _ := message.Data.(*openolt.AlarmIndication)
582 o.sendAlarmIndication(alarmInd, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000583 case NniIndication:
584 msg, _ := message.Data.(NniIndicationMessage)
585 o.sendNniIndication(msg, stream)
586 case PonIndication:
587 msg, _ := message.Data.(PonIndicationMessage)
Pragya Arya2225f202020-01-29 18:05:01 +0530588 pon, _ := o.GetPonById(msg.PonPortID)
589 if msg.OperState == UP {
590 pon.OperState.Event("enable")
591 pon.InternalState.Event("enable")
592 } else if msg.OperState == DOWN {
593 pon.OperState.Event("disable")
594 pon.InternalState.Event("disable")
595 }
David Bainbridge103cf022019-12-16 20:11:35 +0000596 default:
597 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
598 }
599 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700600 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100601 wg.Done()
602 oltLogger.Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700603}
604
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100605// processNniPacketIns handles messages received over the NNI interface
David Bainbridge103cf022019-12-16 20:11:35 +0000606func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700607 oltLogger.WithFields(log.Fields{
608 "nniChannel": o.nniPktInChannel,
Matteo Scandolo401503a2019-12-11 14:48:14 -0800609 }).Debug("Started Processing Packets arriving from the NNI")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700610 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700611
David Bainbridge103cf022019-12-16 20:11:35 +0000612 ch := o.nniPktInChannel
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700613
David Bainbridge103cf022019-12-16 20:11:35 +0000614loop:
615 for {
616 select {
617 case <-ctx.Done():
618 oltLogger.Debug("NNI Indication processing canceled via context")
619 break loop
620 case message, ok := <-ch:
621 if !ok || ctx.Err() != nil {
622 oltLogger.Debug("NNI Indication processing canceled via channel closed")
623 break loop
624 }
625 oltLogger.Tracef("Received packets on NNI Channel")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700626
David Bainbridge103cf022019-12-16 20:11:35 +0000627 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700628
David Bainbridge103cf022019-12-16 20:11:35 +0000629 if err != nil {
630 log.WithFields(log.Fields{
631 "IntfType": "nni",
632 "IntfId": nniId,
633 "Pkt": message.Pkt.Data(),
634 }).Error("Can't find Dst MacAddress in packet")
635 return
636 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700637
David Bainbridge103cf022019-12-16 20:11:35 +0000638 onu, err := o.FindOnuByMacAddress(onuMac)
639 if err != nil {
640 log.WithFields(log.Fields{
641 "IntfType": "nni",
642 "IntfId": nniId,
643 "Pkt": message.Pkt.Data(),
644 "MacAddress": onuMac.String(),
645 }).Error("Can't find ONU with MacAddress")
646 return
647 }
648
649 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
650 if err != nil {
651 log.Error("Fail to add double tag to packet")
652 }
653
654 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
655 IntfType: "nni",
656 IntfId: nniId,
657 Pkt: doubleTaggedPkt.Data()}}
658 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
659 oltLogger.WithFields(log.Fields{
660 "IntfType": data.PktInd.IntfType,
661 "IntfId": nniId,
662 "Pkt": doubleTaggedPkt.Data(),
663 }).Errorf("Fail to send PktInd indication: %v", err)
664 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700665 oltLogger.WithFields(log.Fields{
666 "IntfType": data.PktInd.IntfType,
667 "IntfId": nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700668 "Pkt": doubleTaggedPkt.Data(),
David Bainbridge103cf022019-12-16 20:11:35 +0000669 "OnuSn": onu.Sn(),
670 }).Tracef("Sent PktInd indication")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700671 }
672 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100673 wg.Done()
674 oltLogger.WithFields(log.Fields{
675 "nniChannel": o.nniPktInChannel,
676 }).Warn("Stopped handling NNI Channel")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700677}
678
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700679// returns an ONU with a given Serial Number
680func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200681 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700682 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700683 for _, pon := range o.Pons {
684 for _, onu := range pon.Onus {
685 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700686 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700687 }
688 }
689 }
690
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700691 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-serial-number-%s", serialNumber))
692}
693
William Kurkian9dadc5b2019-10-22 13:51:57 -0400694// returns an ONU with a given interface/Onu Id
695func (o OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200696 // TODO this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400697 // memoizing it will remove the bottleneck
698 for _, pon := range o.Pons {
699 if pon.ID == intfId {
700 for _, onu := range pon.Onus {
701 if onu.ID == onuId {
702 return onu, nil
703 }
704 }
705 }
706 }
707 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-id-%v-%v", intfId, onuId))
708}
709
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700710// returns an ONU with a given Mac Address
711func (o OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200712 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700713 // memoizing it will remove the bottleneck
714 for _, pon := range o.Pons {
715 for _, onu := range pon.Onus {
716 if onu.HwAddress.String() == mac.String() {
Matteo Scandolo27428702019-10-11 16:21:16 -0700717 return onu, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700718 }
719 }
720 }
721
722 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-mac-address-%s", mac))
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700723}
724
Matteo Scandolo4747d292019-08-05 11:50:18 -0700725// GRPC Endpoints
726
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700727func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700728 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700729 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700730 }).Info("Received ActivateOnu call from VOLTHA")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700731
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700732 pon, _ := o.GetPonById(onu.IntfId)
733 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
William Kurkian0418bc82019-11-06 12:16:24 -0500734 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700735
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700736 if err := _onu.OperState.Event("enable"); err != nil {
737 oltLogger.WithFields(log.Fields{
738 "IntfId": _onu.PonPortID,
739 "OnuSn": _onu.Sn(),
740 "OnuId": _onu.ID,
741 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700742 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700743 if err := _onu.InternalState.Event("enable"); err != nil {
744 oltLogger.WithFields(log.Fields{
745 "IntfId": _onu.PonPortID,
746 "OnuSn": _onu.Sn(),
747 "OnuId": _onu.ID,
748 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
749 }
750
751 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
752
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700753 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700754}
755
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700756func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700757 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700758 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700759}
760
Pragya Arya1cbefa42020-01-13 12:15:29 +0530761func (o OltDevice) DeleteOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
762 oltLogger.WithFields(log.Fields{
763 "IntfId": onu.IntfId,
764 "OnuId": onu.OnuId,
765 }).Info("Received DeleteOnu call from VOLTHA")
766
767 pon, err := o.GetPonById(onu.IntfId)
768 if err != nil {
769 oltLogger.WithFields(log.Fields{
770 "OnuId": onu.OnuId,
771 "IntfId": onu.IntfId,
772 "err": err,
773 }).Error("Can't find PonPort")
774 }
775 _onu, err := pon.GetOnuById(onu.OnuId)
776 if err != nil {
777 oltLogger.WithFields(log.Fields{
778 "OnuId": onu.OnuId,
779 "IntfId": onu.IntfId,
780 "err": err,
781 }).Error("Can't find Onu")
782 }
783
784 if err := _onu.InternalState.Event("initialize"); err != nil {
785 oltLogger.WithFields(log.Fields{
786 "IntfId": _onu.PonPortID,
787 "OnuSn": _onu.Sn(),
788 "OnuId": _onu.ID,
789 }).Infof("Failed to transition ONU to initialized state: %s", err.Error())
790 }
791
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700792 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700793}
794
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700795func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700796 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800797 oltLogger.WithFields(log.Fields{
798 "oltId": o.ID,
799 }).Info("Disabling OLT")
800
Matteo Scandolo401503a2019-12-11 14:48:14 -0800801 for _, pon := range o.Pons {
Pragya Arya2225f202020-01-29 18:05:01 +0530802 if pon.InternalState.Current() == "enabled" {
803 // disable PONs
804 msg := Message{
805 Type: PonIndication,
806 Data: PonIndicationMessage{
807 OperState: DOWN,
808 PonPortID: pon.ID,
809 },
810 }
811 o.channel <- msg
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800812 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800813 }
814
Matteo Scandolo401503a2019-12-11 14:48:14 -0800815 // Note that we are not disabling the NNI as the real OLT does not.
816 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800817
818 // disable OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100819 oltMsg := Message{
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700820 Type: OltIndication,
821 Data: OltIndicationMessage{
822 OperState: DOWN,
823 },
824 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100825 o.channel <- oltMsg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700826 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700827}
828
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700829func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700830 oltLogger.Error("DisablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700831 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700832}
833
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100834func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700835 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700836 o.Enable(stream)
837 return nil
838}
839
Pragya Arya2225f202020-01-29 18:05:01 +0530840func (o OltDevice) EnablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
841 oltLogger.Errorf("EnablePonIf request received for PON %d", intf.IntfId)
842 ponID := intf.GetIntfId()
843 msg := Message{
844 Type: PonIndication,
845 Data: PonIndicationMessage{
846 OperState: UP,
847 PonPortID: ponID,
848 },
849 }
850 o.channel <- msg
851
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700852 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700853}
854
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700855func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700856 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700857 "IntfId": flow.AccessIntfId,
858 "OnuId": flow.OnuId,
859 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700860 "InnerVlan": flow.Classifier.IVid,
861 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700862 "FlowType": flow.FlowType,
863 "FlowId": flow.FlowId,
864 "UniID": flow.UniId,
865 "PortNo": flow.PortNo,
Pragya Arya8bdb4532020-03-02 17:08:09 +0530866 }).Tracef("OLT receives FlowAdd")
867
868 flowKey := FlowKey{}
869 if !o.enablePerf {
870 flowKey = FlowKey{ID: flow.FlowId, Direction: flow.FlowType}
871 olt.Flows[flowKey] = *flow
872 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700873
874 if flow.AccessIntfId == -1 {
875 oltLogger.WithFields(log.Fields{
876 "FlowId": flow.FlowId,
877 }).Debugf("This is an OLT flow")
878 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700879 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700880 if err != nil {
881 oltLogger.WithFields(log.Fields{
882 "OnuId": flow.OnuId,
883 "IntfId": flow.AccessIntfId,
884 "err": err,
885 }).Error("Can't find PonPort")
886 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700887 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700888 if err != nil {
889 oltLogger.WithFields(log.Fields{
890 "OnuId": flow.OnuId,
891 "IntfId": flow.AccessIntfId,
892 "err": err,
893 }).Error("Can't find Onu")
894 }
Pragya Arya8bdb4532020-03-02 17:08:09 +0530895 if !o.enablePerf {
896 onu.Flows = append(onu.Flows, flowKey)
897 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700898
899 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700900 Type: FlowUpdate,
901 Data: OnuFlowUpdateMessage{
902 PonPortID: pon.ID,
903 OnuID: onu.ID,
904 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700905 },
906 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700907 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700908 }
909
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700910 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700911}
912
Pragya Arya8bdb4532020-03-02 17:08:09 +0530913// FlowRemove request from VOLTHA
914func (o OltDevice) FlowRemove(_ context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
915 oltLogger.WithFields(log.Fields{
916 "FlowId": flow.FlowId,
917 "FlowType": flow.FlowType,
918 }).Tracef("OLT receives FlowRemove")
919
920 if !o.enablePerf { // remove only if flow were stored
921 flowKey := FlowKey{
922 ID: flow.FlowId,
923 Direction: flow.FlowType,
924 }
925
926 // Check if flow exists
927 storedFlow, ok := o.Flows[flowKey]
928 if !ok {
929 oltLogger.Errorf("Flow %v not found", flow)
930 return new(openolt.Empty), status.Errorf(codes.NotFound, "Flow not found")
931 }
932
933 // if its ONU flow remove it from ONU also
934 if storedFlow.AccessIntfId != -1 {
935 pon := o.Pons[uint32(storedFlow.AccessIntfId)]
936 onu, err := pon.GetOnuById(uint32(storedFlow.OnuId))
937 if err != nil {
938 oltLogger.WithFields(log.Fields{
939 "OnuId": storedFlow.OnuId,
940 "IntfId": storedFlow.AccessIntfId,
941 "err": err,
942 }).Error("ONU not found")
943 return new(openolt.Empty), nil
944 }
945 onu.DeleteFlow(flowKey)
946 }
947
948 // delete from olt flows
949 delete(o.Flows, flowKey)
950 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700951 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700952}
953
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700954func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo18859852020-01-15 13:33:57 -0800955 res := openolt.Heartbeat{HeartbeatSignature: uint32(time.Now().Unix())}
956 oltLogger.WithFields(log.Fields{
957 "signature": res.HeartbeatSignature,
958 }).Trace("HeartbeatCheck")
959 return &res, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700960}
961
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700962func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700963
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700964 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700965 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700966 "PonPorts": o.NumPon,
967 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700968 devinfo := new(openolt.DeviceInfo)
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100969 devinfo.Vendor = common.Options.Olt.Vendor
970 devinfo.Model = common.Options.Olt.Model
971 devinfo.HardwareVersion = common.Options.Olt.HardwareVersion
972 devinfo.FirmwareVersion = common.Options.Olt.FirmwareVersion
973 devinfo.Technology = common.Options.Olt.Technology
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700974 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700975 devinfo.OnuIdStart = 1
976 devinfo.OnuIdEnd = 255
977 devinfo.AllocIdStart = 1024
978 devinfo.AllocIdEnd = 16383
979 devinfo.GemportIdStart = 1024
980 devinfo.GemportIdEnd = 65535
981 devinfo.FlowIdStart = 1
982 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -0700983 devinfo.DeviceSerialNumber = o.SerialNumber
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100984 devinfo.DeviceId = common.Options.Olt.DeviceId
Matteo Scandolo4747d292019-08-05 11:50:18 -0700985
986 return devinfo, nil
987}
988
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700989func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700990 pon, _ := o.GetPonById(omci_msg.IntfId)
991 onu, _ := pon.GetOnuById(omci_msg.OnuId)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700992 oltLogger.WithFields(log.Fields{
993 "IntfId": onu.PonPortID,
994 "OnuId": onu.ID,
995 "OnuSn": onu.Sn(),
996 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700997 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700998 Type: OMCI,
999 Data: OmciMessage{
1000 OnuSN: onu.SerialNumber,
1001 OnuID: onu.ID,
1002 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001003 },
1004 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001005 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001006 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001007}
1008
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001009func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001010 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -07001011 if err != nil {
1012 oltLogger.WithFields(log.Fields{
1013 "OnuId": onuPkt.OnuId,
1014 "IntfId": onuPkt.IntfId,
1015 "err": err,
1016 }).Error("Can't find PonPort")
1017 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001018 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -07001019 if err != nil {
1020 oltLogger.WithFields(log.Fields{
1021 "OnuId": onuPkt.OnuId,
1022 "IntfId": onuPkt.IntfId,
1023 "err": err,
1024 }).Error("Can't find Onu")
1025 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001026
Matteo Scandolo075b1892019-10-07 12:11:07 -07001027 oltLogger.WithFields(log.Fields{
1028 "IntfId": onu.PonPortID,
1029 "OnuId": onu.ID,
1030 "OnuSn": onu.Sn(),
1031 }).Tracef("Received OnuPacketOut")
1032
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001033 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001034 pktType, err := packetHandlers.IsEapolOrDhcp(rawpkt)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001035
Matteo Scandolo075b1892019-10-07 12:11:07 -07001036 msg := Message{
1037 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001038 Data: OnuPacketMessage{
Matteo Scandolo075b1892019-10-07 12:11:07 -07001039 IntfId: onuPkt.IntfId,
1040 OnuId: onuPkt.OnuId,
1041 Packet: rawpkt,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001042 Type: pktType,
Matteo Scandolo075b1892019-10-07 12:11:07 -07001043 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001044 }
Matteo Scandolo075b1892019-10-07 12:11:07 -07001045 onu.Channel <- msg
1046
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001047 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001048}
1049
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001050func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolod02b79b2019-12-05 16:42:13 -08001051 oltLogger.WithFields(log.Fields{
1052 "oltId": o.ID,
1053 }).Info("Shutting down")
1054 go o.RestartOLT()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001055 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001056}
1057
1058func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Pragya Arya6a708d62020-01-01 17:17:20 +05301059 oltLogger.WithFields(log.Fields{
1060 "oltId": o.ID,
1061 }).Info("Received ReenableOlt request from VOLTHA")
1062
Pragya Arya2225f202020-01-29 18:05:01 +05301063 // enable OLT
1064 oltMsg := Message{
1065 Type: OltIndication,
1066 Data: OltIndicationMessage{
1067 OperState: UP,
1068 },
Pragya Arya1881df02020-01-29 18:05:01 +05301069 }
Pragya Arya2225f202020-01-29 18:05:01 +05301070 o.channel <- oltMsg
Pragya Arya6a708d62020-01-01 17:17:20 +05301071
Pragya Arya2225f202020-01-29 18:05:01 +05301072 for _, pon := range o.Pons {
1073 if pon.InternalState.Current() == "disabled" {
1074 msg := Message{
1075 Type: PonIndication,
1076 Data: PonIndicationMessage{
1077 OperState: UP,
1078 PonPortID: pon.ID,
1079 },
1080 }
1081 o.channel <- msg
1082 }
1083 }
Matteo Scandoloe60a5052020-02-07 00:31:14 +00001084
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001085 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001086}
1087
1088func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001089 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
1090
Zdravko Bozakov681364d2019-11-10 14:28:46 +01001091 o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001092 // NOTE should we return an error if sendNniPakcet fails?
1093 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001094}
1095
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001096func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001097 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001098 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001099}
1100
Matteo Scandolo4747d292019-08-05 11:50:18 -07001101func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001102 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001103 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001104}
1105
1106func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001107 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001108 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -07001109}
1110
1111func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001112 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001113 return new(openolt.Empty), nil
1114}
1115
1116func (s OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001117 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001118 return new(openolt.Empty), nil
1119}
1120
Anand S Katti09541352020-01-29 15:54:01 +05301121func (s OltDevice) CreateTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
1122 oltLogger.WithFields(log.Fields{
1123 "OnuId": trafficSchedulers.OnuId,
1124 "IntfId": trafficSchedulers.IntfId,
1125 "OnuPortNo": trafficSchedulers.PortNo,
1126 }).Info("received CreateTrafficSchedulers")
1127
1128 if !s.enablePerf {
1129 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1130 if err != nil {
1131 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1132 return new(openolt.Empty), err
1133 }
1134 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1135 if err != nil {
1136 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1137 return new(openolt.Empty), err
1138 }
1139 onu.TrafficSchedulers = trafficSchedulers
1140 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001141 return new(openolt.Empty), nil
1142}
1143
Anand S Katti09541352020-01-29 15:54:01 +05301144func (s OltDevice) RemoveTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
1145 oltLogger.WithFields(log.Fields{
1146 "OnuId": trafficSchedulers.OnuId,
1147 "IntfId": trafficSchedulers.IntfId,
1148 "OnuPortNo": trafficSchedulers.PortNo,
1149 }).Info("received RemoveTrafficSchedulers")
1150 if !s.enablePerf {
1151 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1152 if err != nil {
1153 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1154 return new(openolt.Empty), err
1155 }
1156 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1157 if err != nil {
1158 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1159 return new(openolt.Empty), err
1160 }
1161
1162 onu.TrafficSchedulers = nil
1163 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001164 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001165}
Scott Baker41724b82020-01-21 19:54:53 -08001166
1167// assumes caller has properly formulated an openolt.AlarmIndication
1168func (o OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
1169 msg := Message{
1170 Type: AlarmIndication,
1171 Data: ind,
1172 }
1173
1174 o.channel <- msg
1175 return nil
1176}