blob: 1832aebdf65fd57e04d4bb0787ec79da86945f51 [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"
Matteo Scandolo401503a2019-12-11 14:48:14 -080023 "github.com/google/gopacket/pcap"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020024 "net"
25 "sync"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010026 "time"
Zdravko Bozakov2da76342019-10-21 09:47:35 +020027
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070028 "github.com/google/gopacket"
29 "github.com/google/gopacket/layers"
Matteo Scandolo4747d292019-08-05 11:50:18 -070030 "github.com/looplab/fsm"
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070031 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070032 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +010033 "github.com/opencord/bbsim/internal/common"
William Kurkian9dadc5b2019-10-22 13:51:57 -040034 omcisim "github.com/opencord/omci-sim"
Matteo Scandolo3de9de02019-11-14 13:40:03 -080035 "github.com/opencord/voltha-protos/v2/go/openolt"
36 "github.com/opencord/voltha-protos/v2/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070037 log "github.com/sirupsen/logrus"
38 "google.golang.org/grpc"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010039 "google.golang.org/grpc/reflection"
Matteo Scandolo4747d292019-08-05 11:50:18 -070040)
41
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070042var oltLogger = log.WithFields(log.Fields{
Matteo Scandolo84f7d482019-08-08 19:00:47 -070043 "module": "OLT",
44})
45
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070046type OltDevice struct {
David Bainbridge103cf022019-12-16 20:11:35 +000047 sync.Mutex
48
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070049 // BBSIM Internals
50 ID int
51 SerialNumber string
52 NumNni int
53 NumPon int
54 NumOnuPerPon int
55 InternalState *fsm.FSM
56 channel chan Message
Zdravko Bozakov681364d2019-11-10 14:28:46 +010057 nniPktInChannel chan *bbsim.PacketMsg // packets coming in from the NNI and going to VOLTHA
Matteo Scandolo401503a2019-12-11 14:48:14 -080058 nniHandle *pcap.Handle // handle on the NNI interface, close it when shutting down the NNI channel
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070059
Matteo Scandoloe33447a2019-10-31 12:38:23 -070060 Delay int
61
Matteo Scandolo27428702019-10-11 16:21:16 -070062 Pons []*PonPort
63 Nnis []*NniPort
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070064
65 // OLT Attributes
66 OperState *fsm.FSM
David Bainbridge103cf022019-12-16 20:11:35 +000067
68 enableContext context.Context
69 enableContextCancel context.CancelFunc
Matteo Scandolo4747d292019-08-05 11:50:18 -070070}
71
Matteo Scandolo27428702019-10-11 16:21:16 -070072var olt OltDevice
Zdravko Bozakov681364d2019-11-10 14:28:46 +010073var oltServer *grpc.Server
Matteo Scandolo84f7d482019-08-08 19:00:47 -070074
Matteo Scandolo27428702019-10-11 16:21:16 -070075func GetOLT() *OltDevice {
76 return &olt
Matteo Scandolo84f7d482019-08-08 19:00:47 -070077}
78
Zdravko Bozakov681364d2019-11-10 14:28:46 +010079func CreateOLT(oltId int, nni int, pon int, onuPerPon int, sTag int, cTagInit int, auth bool, dhcp bool, delay int, isMock bool) *OltDevice {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070080 oltLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070081 "ID": oltId,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070082 "NumNni": nni,
83 "NumPon": pon,
84 "NumOnuPerPon": onuPerPon,
Matteo Scandolo4747d292019-08-05 11:50:18 -070085 }).Debug("CreateOLT")
86
Matteo Scandolo84f7d482019-08-08 19:00:47 -070087 olt = OltDevice{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070088 ID: oltId,
89 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", oltId),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070090 OperState: getOperStateFSM(func(e *fsm.Event) {
91 oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
92 }),
Zdravko Bozakov681364d2019-11-10 14:28:46 +010093 NumNni: nni,
94 NumPon: pon,
95 NumOnuPerPon: onuPerPon,
96 Pons: []*PonPort{},
97 Nnis: []*NniPort{},
98 Delay: delay,
Matteo Scandolo4747d292019-08-05 11:50:18 -070099 }
100
101 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700102 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700103 olt.InternalState = fsm.NewFSM(
104 "created",
105 fsm.Events{
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800106 {Name: "initialize", Src: []string{"created", "deleted"}, Dst: "initialized"},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100107 {Name: "enable", Src: []string{"initialized", "disabled"}, Dst: "enabled"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700108 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
Mahir Gunyel6dad4452020-01-06 12:59:04 -0800109 //delete event in enabled state below is for reboot OLT case.
110 {Name: "delete", Src: []string{"disabled", "enabled"}, Dst: "deleted"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700111 },
112 fsm.Callbacks{
113 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700114 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700115 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100116 "enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
Matteo Scandolo4747d292019-08-05 11:50:18 -0700117 },
118 )
119
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700120 if isMock != true {
121 // create NNI Port
122 nniPort, err := CreateNNI(&olt)
123 if err != nil {
124 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
125 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700126
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700127 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700128 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700129
Matteo Scandolo4747d292019-08-05 11:50:18 -0700130 // create PON ports
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700131 availableCTag := cTagInit
Matteo Scandolo4747d292019-08-05 11:50:18 -0700132 for i := 0; i < pon; i++ {
133 p := PonPort{
134 NumOnu: olt.NumOnuPerPon,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700135 ID: uint32(i),
136 Type: "pon",
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700137 Olt: olt,
Matteo Scandolo27428702019-10-11 16:21:16 -0700138 Onus: []*Onu{},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700139 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700140 p.OperState = getOperStateFSM(func(e *fsm.Event) {
141 oltLogger.WithFields(log.Fields{
142 "ID": p.ID,
143 }).Debugf("Changing PON Port OperState from %s to %s", e.Src, e.Dst)
144 })
Matteo Scandolo4747d292019-08-05 11:50:18 -0700145
146 // create ONU devices
147 for j := 0; j < onuPerPon; j++ {
Matteo Scandoloc1147092019-10-29 09:38:33 -0700148 o := CreateONU(olt, p, uint32(j+1), sTag, availableCTag, auth, dhcp)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700149 p.Onus = append(p.Onus, o)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700150 availableCTag = availableCTag + 1
Matteo Scandolo4747d292019-08-05 11:50:18 -0700151 }
152
Matteo Scandolo27428702019-10-11 16:21:16 -0700153 olt.Pons = append(olt.Pons, &p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700154 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100155
Matteo Scandolod32c3822019-11-26 15:57:46 -0700156 if isMock != true {
157 if err := olt.InternalState.Event("initialize"); err != nil {
158 log.Errorf("Error initializing OLT: %v", err)
159 return nil
160 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100161 }
162
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700163 return &olt
164}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700165
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100166func (o *OltDevice) InitOlt() error {
167
168 if oltServer == nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800169 oltServer, _ = o.newOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100170 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800171 // FIXME there should never be a server running if we are initializing the OLT
172 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100173 }
174
175 // create new channel for processOltMessages Go routine
176 o.channel = make(chan Message)
177
178 o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
179 // FIXME we are assuming we have only one NNI
180 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800181 // NOTE we want to make sure the state is down when we initialize the OLT,
182 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
183 // in-band management
184 o.Nnis[0].OperState.SetState("down")
185 ch, handle, err := o.Nnis[0].NewVethChan()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100186 if err == nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800187 oltLogger.WithFields(log.Fields{
188 "Type": o.Nnis[0].Type,
189 "IntfId": o.Nnis[0].ID,
190 "OperState": o.Nnis[0].OperState.Current(),
191 }).Info("NNI Channel created")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100192 o.nniPktInChannel = ch
Matteo Scandolo401503a2019-12-11 14:48:14 -0800193 o.nniHandle = handle
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100194 } else {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800195 oltLogger.Errorf("Error getting NNI channel: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100196 }
197 }
198
199 for i := range olt.Pons {
200 for _, onu := range olt.Pons[i].Onus {
201 if err := onu.InternalState.Event("initialize"); err != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800202 oltLogger.Errorf("Error initializing ONU: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100203 return err
204 }
205 }
206 }
207
208 return nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700209}
210
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800211func (o *OltDevice) RestartOLT() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100212
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800213 rebootDelay := common.Options.Olt.OltRebootDelay
214
215 oltLogger.WithFields(log.Fields{
216 "oltId": o.ID,
217 }).Infof("Simulating OLT restart... (%ds)", rebootDelay)
218
219 // transition internal state to deleted
220 if err := o.InternalState.Event("delete"); err != nil {
221 oltLogger.WithFields(log.Fields{
222 "oltId": o.ID,
223 }).Errorf("Error deleting OLT: %v", err)
224 return err
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100225 }
226
227 // TODO handle hard poweroff (i.e. no indications sent to Voltha) vs soft poweroff
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800228 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
229 if err := o.StopOltServer(); err != nil {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100230 return err
231 }
232
233 // terminate the OLT's processOltMessages go routine
234 close(o.channel)
235 // terminate the OLT's processNniPacketIns go routine
Matteo Scandolo401503a2019-12-11 14:48:14 -0800236 o.nniHandle.Close()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100237 close(o.nniPktInChannel)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100238
Matteo Scandolo401503a2019-12-11 14:48:14 -0800239 for i := range olt.Pons {
240 for _, onu := range olt.Pons[i].Onus {
241 // NOTE while the olt is off, restore the ONU to the initial state
242 onu.InternalState.SetState("created")
243 }
244 }
245
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100246 time.Sleep(time.Duration(rebootDelay) * time.Second)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100247
248 if err := o.InternalState.Event("initialize"); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800249 oltLogger.WithFields(log.Fields{
250 "oltId": o.ID,
251 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100252 return err
253 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800254 oltLogger.WithFields(log.Fields{
255 "oltId": o.ID,
256 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100257 return nil
258}
259
260// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800261func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100262 address := common.Options.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700263 lis, err := net.Listen("tcp", address)
264 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700265 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700266 }
267 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100268
Matteo Scandolo4747d292019-08-05 11:50:18 -0700269 openolt.RegisterOpenoltServer(grpcServer, o)
270
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100271 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700272
Matteo Scandolo4747d292019-08-05 11:50:18 -0700273 go grpcServer.Serve(lis)
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100274 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700275
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100276 return grpcServer, nil
277}
278
279// StopOltServer stops the OpenOLT grpc server
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800280func (o *OltDevice) StopOltServer() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100281 // TODO handle poweroff vs graceful shutdown
282 if oltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800283 oltLogger.WithFields(log.Fields{
284 "oltId": o.SerialNumber,
285 }).Warnf("Stopping OLT gRPC server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100286 oltServer.Stop()
287 oltServer = nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700288 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800289
Matteo Scandolo4747d292019-08-05 11:50:18 -0700290 return nil
291}
292
293// Device Methods
294
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100295// Enable implements the OpenOLT EnableIndicationServer functionality
296func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700297 oltLogger.Debug("Enable OLT called")
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700298
David Bainbridge103cf022019-12-16 20:11:35 +0000299 // If enabled has already been called then an enabled context has
300 // been created. If this is the case then we want to cancel all the
301 // proessing loops associated with that enable before we recreate
302 // new ones
303 o.Lock()
304 if o.enableContext != nil && o.enableContextCancel != nil {
305 o.enableContextCancel()
306 }
307 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
308 o.Unlock()
309
Matteo Scandolo4747d292019-08-05 11:50:18 -0700310 wg := sync.WaitGroup{}
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800311 wg.Add(3)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700312
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100313 // create Go routine to process all OLT events
David Bainbridge103cf022019-12-16 20:11:35 +0000314 go o.processOltMessages(o.enableContext, stream, &wg)
315 go o.processNniPacketIns(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700316
317 // enable the OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100318 oltMsg := Message{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700319 Type: OltIndication,
320 Data: OltIndicationMessage{
321 OperState: UP,
322 },
323 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100324 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700325
326 // send NNI Port Indications
327 for _, nni := range o.Nnis {
328 msg := Message{
329 Type: NniIndication,
330 Data: NniIndicationMessage{
331 OperState: UP,
332 NniPortID: nni.ID,
333 },
334 }
335 o.channel <- msg
336 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100337
David Bainbridge103cf022019-12-16 20:11:35 +0000338 go o.processOmciMessages(o.enableContext, &wg)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100339
Matteo Scandolo4747d292019-08-05 11:50:18 -0700340 // send PON Port indications
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100341 for i, pon := range o.Pons {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700342 msg := Message{
343 Type: PonIndication,
344 Data: PonIndicationMessage{
345 OperState: UP,
346 PonPortID: pon.ID,
347 },
348 }
349 o.channel <- msg
350
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100351 for _, onu := range o.Pons[i].Onus {
David Bainbridge103cf022019-12-16 20:11:35 +0000352 go onu.ProcessOnuMessages(o.enableContext, stream, nil)
353 if onu.InternalState.Current() != "initialized" {
354 continue
355 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100356 if err := onu.InternalState.Event("discover"); err != nil {
357 log.Errorf("Error discover ONU: %v", err)
358 return err
Matteo Scandolo4747d292019-08-05 11:50:18 -0700359 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700360 }
361 }
362
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800363 oltLogger.Debug("Enable OLT Done")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700364 wg.Wait()
365 return nil
366}
367
David Bainbridge103cf022019-12-16 20:11:35 +0000368func (o *OltDevice) processOmciMessages(ctx context.Context, wg *sync.WaitGroup) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400369 ch := omcisim.GetChannel()
370
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100371 oltLogger.Debug("Starting OMCI Indication Channel")
William Kurkian9dadc5b2019-10-22 13:51:57 -0400372
David Bainbridge103cf022019-12-16 20:11:35 +0000373loop:
374 for {
375 select {
376 case <-ctx.Done():
377 oltLogger.Debug("OMCI processing canceled via context")
378 break loop
379 case message, ok := <-ch:
380 if !ok || ctx.Err() != nil {
381 oltLogger.Debug("OMCI processing canceled via channel close")
382 break loop
383 }
384 onuId := message.Data.OnuId
385 intfId := message.Data.IntfId
386 onu, err := o.FindOnuById(intfId, onuId)
387 if err != nil {
388 oltLogger.Errorf("Failed to find onu: %v", err)
389 continue
390 }
391 go onu.processOmciMessage(message)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400392 }
William Kurkian9dadc5b2019-10-22 13:51:57 -0400393 }
David Bainbridge103cf022019-12-16 20:11:35 +0000394
395 wg.Done()
William Kurkian9dadc5b2019-10-22 13:51:57 -0400396}
397
Matteo Scandolo4747d292019-08-05 11:50:18 -0700398// Helpers method
399
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700400func (o OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700401 for _, pon := range o.Pons {
402 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700403 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700404 }
405 }
406 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
407}
408
409func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
410 for _, nni := range o.Nnis {
411 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700412 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700413 }
414 }
415 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
416}
417
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100418func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700419 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
420 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700421 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800422 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700423 }
424
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700425 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700426 "OperState": msg.OperState,
427 }).Debug("Sent Indication_OltInd")
428}
429
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100430func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700431 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800432 if msg.OperState == UP {
433 if err := nni.OperState.Event("enable"); err != nil {
434 log.WithFields(log.Fields{
435 "Type": nni.Type,
436 "IntfId": nni.ID,
437 "OperState": nni.OperState.Current(),
438 }).Errorf("Can't move NNI Port to enabled state: %v", err)
439 }
440 } else if msg.OperState == DOWN {
441 if err := nni.OperState.Event("disable"); err != nil {
442 log.WithFields(log.Fields{
443 "Type": nni.Type,
444 "IntfId": nni.ID,
445 "OperState": nni.OperState.Current(),
446 }).Errorf("Can't move NNI Port to disable state: %v", err)
447 }
448 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700449 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700450 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700451 Type: nni.Type,
452 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700453 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700454 }}
455
456 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700457 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800458 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700459 }
460
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700461 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700462 "Type": nni.Type,
463 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700464 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700465 }).Debug("Sent Indication_IntfOperInd for NNI")
466}
467
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100468func (o *OltDevice) sendPonIndication(msg PonIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700469 pon, _ := o.GetPonById(msg.PonPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800470 if msg.OperState == UP {
471 if err := pon.OperState.Event("enable"); err != nil {
472 log.WithFields(log.Fields{
473 "Type": pon.Type,
474 "IntfId": pon.ID,
475 "OperState": pon.OperState.Current(),
476 }).Errorf("Can't move PON Port to enable state: %v", err)
477 }
478 } else if msg.OperState == DOWN {
479 if err := pon.OperState.Event("disable"); err != nil {
480 log.WithFields(log.Fields{
481 "Type": pon.Type,
482 "IntfId": pon.ID,
483 "OperState": pon.OperState.Current(),
484 }).Errorf("Can't move PON Port to disable state: %v", err)
485 }
486 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700487 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700488 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700489 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700490 }}
491
492 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700493 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800494 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700495 }
496
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700497 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700498 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700499 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700500 }).Debug("Sent Indication_IntfInd")
501
502 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700503 Type: pon.Type,
504 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700505 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700506 }}
507
508 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700509 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800510 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700511 }
512
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700513 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700514 "Type": pon.Type,
515 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700516 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700517 }).Debug("Sent Indication_IntfOperInd for PON")
518}
519
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100520// processOltMessages handles messages received over the OpenOLT interface
David Bainbridge103cf022019-12-16 20:11:35 +0000521func (o *OltDevice) processOltMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100522 oltLogger.Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000523 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700524
David Bainbridge103cf022019-12-16 20:11:35 +0000525loop:
526 for {
527 select {
528 case <-ctx.Done():
529 oltLogger.Debug("OLT Indication processing canceled via context")
530 break loop
531 case message, ok := <-ch:
532 if !ok || ctx.Err() != nil {
533 oltLogger.Debug("OLT Indication processing canceled via closed channel")
534 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700535 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700536
David Bainbridge103cf022019-12-16 20:11:35 +0000537 oltLogger.WithFields(log.Fields{
538 "oltId": o.ID,
539 "messageType": message.Type,
540 }).Trace("Received message")
541
542 switch message.Type {
543 case OltIndication:
544 msg, _ := message.Data.(OltIndicationMessage)
545 if msg.OperState == UP {
546 o.InternalState.Event("enable")
547 o.OperState.Event("enable")
548 } else if msg.OperState == DOWN {
549 o.InternalState.Event("disable")
550 o.OperState.Event("disable")
551 }
552 o.sendOltIndication(msg, stream)
553 case NniIndication:
554 msg, _ := message.Data.(NniIndicationMessage)
555 o.sendNniIndication(msg, stream)
556 case PonIndication:
557 msg, _ := message.Data.(PonIndicationMessage)
558 o.sendPonIndication(msg, stream)
559 default:
560 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
561 }
562 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700563 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100564 wg.Done()
565 oltLogger.Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700566}
567
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100568// processNniPacketIns handles messages received over the NNI interface
David Bainbridge103cf022019-12-16 20:11:35 +0000569func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700570 oltLogger.WithFields(log.Fields{
571 "nniChannel": o.nniPktInChannel,
Matteo Scandolo401503a2019-12-11 14:48:14 -0800572 }).Debug("Started Processing Packets arriving from the NNI")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700573 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700574
David Bainbridge103cf022019-12-16 20:11:35 +0000575 ch := o.nniPktInChannel
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700576
David Bainbridge103cf022019-12-16 20:11:35 +0000577loop:
578 for {
579 select {
580 case <-ctx.Done():
581 oltLogger.Debug("NNI Indication processing canceled via context")
582 break loop
583 case message, ok := <-ch:
584 if !ok || ctx.Err() != nil {
585 oltLogger.Debug("NNI Indication processing canceled via channel closed")
586 break loop
587 }
588 oltLogger.Tracef("Received packets on NNI Channel")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700589
David Bainbridge103cf022019-12-16 20:11:35 +0000590 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700591
David Bainbridge103cf022019-12-16 20:11:35 +0000592 if err != nil {
593 log.WithFields(log.Fields{
594 "IntfType": "nni",
595 "IntfId": nniId,
596 "Pkt": message.Pkt.Data(),
597 }).Error("Can't find Dst MacAddress in packet")
598 return
599 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700600
David Bainbridge103cf022019-12-16 20:11:35 +0000601 onu, err := o.FindOnuByMacAddress(onuMac)
602 if err != nil {
603 log.WithFields(log.Fields{
604 "IntfType": "nni",
605 "IntfId": nniId,
606 "Pkt": message.Pkt.Data(),
607 "MacAddress": onuMac.String(),
608 }).Error("Can't find ONU with MacAddress")
609 return
610 }
611
612 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
613 if err != nil {
614 log.Error("Fail to add double tag to packet")
615 }
616
617 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
618 IntfType: "nni",
619 IntfId: nniId,
620 Pkt: doubleTaggedPkt.Data()}}
621 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
622 oltLogger.WithFields(log.Fields{
623 "IntfType": data.PktInd.IntfType,
624 "IntfId": nniId,
625 "Pkt": doubleTaggedPkt.Data(),
626 }).Errorf("Fail to send PktInd indication: %v", err)
627 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700628 oltLogger.WithFields(log.Fields{
629 "IntfType": data.PktInd.IntfType,
630 "IntfId": nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700631 "Pkt": doubleTaggedPkt.Data(),
David Bainbridge103cf022019-12-16 20:11:35 +0000632 "OnuSn": onu.Sn(),
633 }).Tracef("Sent PktInd indication")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700634 }
635 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100636 wg.Done()
637 oltLogger.WithFields(log.Fields{
638 "nniChannel": o.nniPktInChannel,
639 }).Warn("Stopped handling NNI Channel")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700640}
641
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700642// returns an ONU with a given Serial Number
643func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200644 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700645 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700646 for _, pon := range o.Pons {
647 for _, onu := range pon.Onus {
648 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700649 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700650 }
651 }
652 }
653
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700654 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-serial-number-%s", serialNumber))
655}
656
William Kurkian9dadc5b2019-10-22 13:51:57 -0400657// returns an ONU with a given interface/Onu Id
658func (o OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200659 // TODO this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400660 // memoizing it will remove the bottleneck
661 for _, pon := range o.Pons {
662 if pon.ID == intfId {
663 for _, onu := range pon.Onus {
664 if onu.ID == onuId {
665 return onu, nil
666 }
667 }
668 }
669 }
670 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-id-%v-%v", intfId, onuId))
671}
672
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700673// returns an ONU with a given Mac Address
674func (o OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*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
677 for _, pon := range o.Pons {
678 for _, onu := range pon.Onus {
679 if onu.HwAddress.String() == mac.String() {
Matteo Scandolo27428702019-10-11 16:21:16 -0700680 return onu, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700681 }
682 }
683 }
684
685 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-mac-address-%s", mac))
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700686}
687
Matteo Scandolo4747d292019-08-05 11:50:18 -0700688// GRPC Endpoints
689
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700690func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700691 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700692 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700693 }).Info("Received ActivateOnu call from VOLTHA")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700694
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700695 pon, _ := o.GetPonById(onu.IntfId)
696 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
William Kurkian0418bc82019-11-06 12:16:24 -0500697 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700698
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700699 if err := _onu.OperState.Event("enable"); err != nil {
700 oltLogger.WithFields(log.Fields{
701 "IntfId": _onu.PonPortID,
702 "OnuSn": _onu.Sn(),
703 "OnuId": _onu.ID,
704 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700705 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700706 if err := _onu.InternalState.Event("enable"); err != nil {
707 oltLogger.WithFields(log.Fields{
708 "IntfId": _onu.PonPortID,
709 "OnuSn": _onu.Sn(),
710 "OnuId": _onu.ID,
711 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
712 }
713
714 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
715
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700716 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700717}
718
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700719func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700720 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700721 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700722}
723
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700724func (o OltDevice) DeleteOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700725 oltLogger.Error("DeleteOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700726 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700727}
728
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700729func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700730 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800731 oltLogger.WithFields(log.Fields{
732 "oltId": o.ID,
733 }).Info("Disabling OLT")
734
Matteo Scandolo401503a2019-12-11 14:48:14 -0800735 for _, pon := range o.Pons {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800736 // disable PONs
737 msg := Message{
738 Type: PonIndication,
739 Data: PonIndicationMessage{
740 OperState: DOWN,
741 PonPortID: pon.ID,
742 },
743 }
744
745 o.channel <- msg
746 }
747
Matteo Scandolo401503a2019-12-11 14:48:14 -0800748 // Note that we are not disabling the NNI as the real OLT does not.
749 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800750
751 // disable OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100752 oltMsg := Message{
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700753 Type: OltIndication,
754 Data: OltIndicationMessage{
755 OperState: DOWN,
756 },
757 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100758 o.channel <- oltMsg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700759 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700760}
761
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700762func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700763 oltLogger.Error("DisablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700764 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700765}
766
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100767func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700768 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700769 o.Enable(stream)
770 return nil
771}
772
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700773func (o OltDevice) EnablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700774 oltLogger.Error("EnablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700775 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700776}
777
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700778func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700779 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700780 "IntfId": flow.AccessIntfId,
781 "OnuId": flow.OnuId,
782 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700783 "InnerVlan": flow.Classifier.IVid,
784 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700785 "FlowType": flow.FlowType,
786 "FlowId": flow.FlowId,
787 "UniID": flow.UniId,
788 "PortNo": flow.PortNo,
789 }).Tracef("OLT receives Flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700790 // TODO optionally store flows somewhere
791
792 if flow.AccessIntfId == -1 {
793 oltLogger.WithFields(log.Fields{
794 "FlowId": flow.FlowId,
795 }).Debugf("This is an OLT flow")
796 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700797 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700798 if err != nil {
799 oltLogger.WithFields(log.Fields{
800 "OnuId": flow.OnuId,
801 "IntfId": flow.AccessIntfId,
802 "err": err,
803 }).Error("Can't find PonPort")
804 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700805 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700806 if err != nil {
807 oltLogger.WithFields(log.Fields{
808 "OnuId": flow.OnuId,
809 "IntfId": flow.AccessIntfId,
810 "err": err,
811 }).Error("Can't find Onu")
812 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700813
814 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700815 Type: FlowUpdate,
816 Data: OnuFlowUpdateMessage{
817 PonPortID: pon.ID,
818 OnuID: onu.ID,
819 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700820 },
821 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700822 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700823 }
824
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700825 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700826}
827
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700828func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
829 oltLogger.Tracef("received FlowRemove")
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700830 // TODO store flows somewhere
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700831 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700832}
833
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700834func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700835 oltLogger.Error("HeartbeatCheck not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700836 return new(openolt.Heartbeat), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700837}
838
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700839func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700840
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700841 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700842 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700843 "PonPorts": o.NumPon,
844 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700845 devinfo := new(openolt.DeviceInfo)
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100846 devinfo.Vendor = common.Options.Olt.Vendor
847 devinfo.Model = common.Options.Olt.Model
848 devinfo.HardwareVersion = common.Options.Olt.HardwareVersion
849 devinfo.FirmwareVersion = common.Options.Olt.FirmwareVersion
850 devinfo.Technology = common.Options.Olt.Technology
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700851 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700852 devinfo.OnuIdStart = 1
853 devinfo.OnuIdEnd = 255
854 devinfo.AllocIdStart = 1024
855 devinfo.AllocIdEnd = 16383
856 devinfo.GemportIdStart = 1024
857 devinfo.GemportIdEnd = 65535
858 devinfo.FlowIdStart = 1
859 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -0700860 devinfo.DeviceSerialNumber = o.SerialNumber
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100861 devinfo.DeviceId = common.Options.Olt.DeviceId
Matteo Scandolo4747d292019-08-05 11:50:18 -0700862
863 return devinfo, nil
864}
865
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700866func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700867 pon, _ := o.GetPonById(omci_msg.IntfId)
868 onu, _ := pon.GetOnuById(omci_msg.OnuId)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700869 oltLogger.WithFields(log.Fields{
870 "IntfId": onu.PonPortID,
871 "OnuId": onu.ID,
872 "OnuSn": onu.Sn(),
873 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700874 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700875 Type: OMCI,
876 Data: OmciMessage{
877 OnuSN: onu.SerialNumber,
878 OnuID: onu.ID,
879 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700880 },
881 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700882 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700883 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700884}
885
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700886func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700887 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700888 if err != nil {
889 oltLogger.WithFields(log.Fields{
890 "OnuId": onuPkt.OnuId,
891 "IntfId": onuPkt.IntfId,
892 "err": err,
893 }).Error("Can't find PonPort")
894 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700895 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700896 if err != nil {
897 oltLogger.WithFields(log.Fields{
898 "OnuId": onuPkt.OnuId,
899 "IntfId": onuPkt.IntfId,
900 "err": err,
901 }).Error("Can't find Onu")
902 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700903
Matteo Scandolo075b1892019-10-07 12:11:07 -0700904 oltLogger.WithFields(log.Fields{
905 "IntfId": onu.PonPortID,
906 "OnuId": onu.ID,
907 "OnuSn": onu.Sn(),
908 }).Tracef("Received OnuPacketOut")
909
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700910 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700911 pktType, err := packetHandlers.IsEapolOrDhcp(rawpkt)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700912
Matteo Scandolo075b1892019-10-07 12:11:07 -0700913 msg := Message{
914 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700915 Data: OnuPacketMessage{
Matteo Scandolo075b1892019-10-07 12:11:07 -0700916 IntfId: onuPkt.IntfId,
917 OnuId: onuPkt.OnuId,
918 Packet: rawpkt,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700919 Type: pktType,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700920 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700921 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700922 onu.Channel <- msg
923
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700924 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700925}
926
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700927func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800928 oltLogger.WithFields(log.Fields{
929 "oltId": o.ID,
930 }).Info("Shutting down")
931 go o.RestartOLT()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700932 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700933}
934
935func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700936 oltLogger.Error("ReenableOlt not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700937 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700938}
939
940func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700941 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
942
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100943 o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700944 // NOTE should we return an error if sendNniPakcet fails?
945 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700946}
947
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700948func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700949 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700950 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700951}
952
Matteo Scandolo4747d292019-08-05 11:50:18 -0700953func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700954 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700955 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700956}
957
958func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700959 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700960 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -0700961}
962
963func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700964 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700965 return new(openolt.Empty), nil
966}
967
968func (s OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700969 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700970 return new(openolt.Empty), nil
971}
972
973func (s OltDevice) CreateTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700974 oltLogger.Info("received CreateTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700975 return new(openolt.Empty), nil
976}
977
978func (s OltDevice) RemoveTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700979 oltLogger.Info("received RemoveTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700980 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700981}