blob: a9420dea21ae01b6e43c5b13168e65ef609b7836 [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"
Matteo Scandolo4a036262020-08-17 15:56:13 -070021 "encoding/hex"
Matteo Scandolo4747d292019-08-05 11:50:18 -070022 "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"
Matteo Scandolof65e6872020-04-15 15:18:43 -070036 "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
Pragya Arya324337e2020-02-20 14:35:08 +053064 EventChannel chan common.Event
65 PublishEvents bool
Pragya Arya996a0892020-03-09 21:47:52 +053066 PortStatsInterval int
Matteo Scandoloe33447a2019-10-31 12:38:23 -070067
Matteo Scandolo27428702019-10-11 16:21:16 -070068 Pons []*PonPort
69 Nnis []*NniPort
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070070
71 // OLT Attributes
72 OperState *fsm.FSM
David Bainbridge103cf022019-12-16 20:11:35 +000073
74 enableContext context.Context
75 enableContextCancel context.CancelFunc
Pragya Arya1cbefa42020-01-13 12:15:29 +053076
Matteo Scandolo4a036262020-08-17 15:56:13 -070077 OpenoltStream openolt.Openolt_EnableIndicationServer
Anand S Katti09541352020-01-29 15:54:01 +053078 enablePerf bool
Matteo Scandolo4747d292019-08-05 11:50:18 -070079}
80
Matteo Scandolo27428702019-10-11 16:21:16 -070081var olt OltDevice
Zdravko Bozakov681364d2019-11-10 14:28:46 +010082var oltServer *grpc.Server
Matteo Scandolo84f7d482019-08-08 19:00:47 -070083
Matteo Scandolo27428702019-10-11 16:21:16 -070084func GetOLT() *OltDevice {
85 return &olt
Matteo Scandolo84f7d482019-08-08 19:00:47 -070086}
87
Matteo Scandolo4a036262020-08-17 15:56:13 -070088func CreateOLT(options common.GlobalConfig, services []common.ServiceYaml, isMock bool) *OltDevice {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070089 oltLogger.WithFields(log.Fields{
Pragya Arya996a0892020-03-09 21:47:52 +053090 "ID": options.Olt.ID,
91 "NumNni": options.Olt.NniPorts,
92 "NumPon": options.Olt.PonPorts,
93 "NumOnuPerPon": options.Olt.OnusPonPort,
Matteo Scandolo4747d292019-08-05 11:50:18 -070094 }).Debug("CreateOLT")
95
Matteo Scandolo84f7d482019-08-08 19:00:47 -070096 olt = OltDevice{
Pragya Arya996a0892020-03-09 21:47:52 +053097 ID: options.Olt.ID,
98 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", options.Olt.ID),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070099 OperState: getOperStateFSM(func(e *fsm.Event) {
100 oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
101 }),
Pragya Arya996a0892020-03-09 21:47:52 +0530102 NumNni: int(options.Olt.NniPorts),
103 NumPon: int(options.Olt.PonPorts),
104 NumOnuPerPon: int(options.Olt.OnusPonPort),
105 Pons: []*PonPort{},
106 Nnis: []*NniPort{},
107 Delay: options.BBSim.Delay,
108 Flows: make(map[FlowKey]openolt.Flow),
109 enablePerf: options.BBSim.EnablePerf,
110 PublishEvents: options.BBSim.Events,
111 PortStatsInterval: options.Olt.PortStatsInterval,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700112 }
113
Pragya Arya996a0892020-03-09 21:47:52 +0530114 if val, ok := ControlledActivationModes[options.BBSim.ControlledActivation]; ok {
Pragya Arya2225f202020-01-29 18:05:01 +0530115 olt.ControlledActivation = val
116 } else {
Matteo Scandoloadc72a82020-09-08 18:46:08 -0700117 // FIXME throw an error if the ControlledActivation is not valid
Pragya Arya2225f202020-01-29 18:05:01 +0530118 oltLogger.Warn("Unknown ControlledActivation Mode given, running in Default mode")
119 olt.ControlledActivation = Default
120 }
121
Matteo Scandolo4747d292019-08-05 11:50:18 -0700122 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700123 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700124 olt.InternalState = fsm.NewFSM(
125 "created",
126 fsm.Events{
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800127 {Name: "initialize", Src: []string{"created", "deleted"}, Dst: "initialized"},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100128 {Name: "enable", Src: []string{"initialized", "disabled"}, Dst: "enabled"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700129 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700130 // delete event in enabled state below is for reboot OLT case.
Mahir Gunyel6dad4452020-01-06 12:59:04 -0800131 {Name: "delete", Src: []string{"disabled", "enabled"}, Dst: "deleted"},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700132 },
133 fsm.Callbacks{
134 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700135 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700136 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100137 "enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
Matteo Scandolo4747d292019-08-05 11:50:18 -0700138 },
139 )
140
Shrey Baid688b4242020-07-10 20:40:10 +0530141 if !isMock {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700142 // create NNI Port
143 nniPort, err := CreateNNI(&olt)
144 if err != nil {
145 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
146 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700147
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700148 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700149 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700150
Matteo Scandolo4a036262020-08-17 15:56:13 -0700151 // Create device and Services
152
153 nextCtag := map[string]int{}
154 nextStag := map[string]int{}
155
Matteo Scandolo4747d292019-08-05 11:50:18 -0700156 // create PON ports
Matteo Scandolo4a036262020-08-17 15:56:13 -0700157 for i := 0; i < olt.NumPon; i++ {
158 p := CreatePonPort(&olt, uint32(i))
Matteo Scandolo4747d292019-08-05 11:50:18 -0700159
Matteo Scandolo4a036262020-08-17 15:56:13 -0700160 // create ONU devices
161 for j := 0; j < olt.NumOnuPerPon; j++ {
162 delay := time.Duration(olt.Delay*j) * time.Millisecond
163 o := CreateONU(&olt, p, uint32(j+1), delay, isMock)
Matteo Scandolof65e6872020-04-15 15:18:43 -0700164
Matteo Scandolo4a036262020-08-17 15:56:13 -0700165 for k, s := range common.Services {
166
167 // find the correct cTag for this service
168 if _, ok := nextCtag[s.Name]; !ok {
169 // it's the first time we iterate over this service,
170 // so we start from the config value
171 nextCtag[s.Name] = s.CTag
172 } else {
173 // we have a previous value, so we check it
174 // if Allocation is unique, we increment,
175 // otherwise (shared) we do nothing
176 if s.CTagAllocation == common.TagAllocationUnique.String() {
177 nextCtag[s.Name] = nextCtag[s.Name] + 1
178 }
179 }
180
181 // find the correct sTag for this service
182 if _, ok := nextStag[s.Name]; !ok {
183 nextStag[s.Name] = s.STag
184 } else {
185 if s.STagAllocation == common.TagAllocationUnique.String() {
186 nextStag[s.Name] = nextStag[s.Name] + 1
187 }
188 }
189
190 mac := net.HardwareAddr{0x2e, 0x60, byte(olt.ID), byte(p.ID), byte(o.ID), byte(k)}
191 service, err := NewService(s.Name, mac, o, nextCtag[s.Name], nextStag[s.Name],
192 s.NeedsEapol, s.NeedsDchp, s.NeedsIgmp, s.TechnologyProfileID, s.UniTagMatch,
193 s.ConfigureMacAddress, s.UsPonCTagPriority, s.UsPonSTagPriority, s.DsPonCTagPriority, s.DsPonSTagPriority)
194
195 if err != nil {
196 oltLogger.WithFields(log.Fields{
197 "Err": err.Error(),
198 }).Fatal("Can't create Service")
199 }
200
201 o.Services = append(o.Services, service)
Matteo Scandolof65e6872020-04-15 15:18:43 -0700202 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700203 p.Onus = append(p.Onus, o)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700204 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700205 olt.Pons = append(olt.Pons, p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700206 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100207
Shrey Baid688b4242020-07-10 20:40:10 +0530208 if !isMock {
Matteo Scandolod32c3822019-11-26 15:57:46 -0700209 if err := olt.InternalState.Event("initialize"); err != nil {
210 log.Errorf("Error initializing OLT: %v", err)
211 return nil
212 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100213 }
214
Pragya Arya324337e2020-02-20 14:35:08 +0530215 if olt.PublishEvents {
216 log.Debugf("BBSim event publishing is enabled")
217 // Create a channel to write event messages
218 olt.EventChannel = make(chan common.Event, 100)
219 }
220
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700221 return &olt
222}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700223
Shrey Baid688b4242020-07-10 20:40:10 +0530224func (o *OltDevice) InitOlt() {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100225
226 if oltServer == nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800227 oltServer, _ = o.newOltServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100228 } else {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800229 // FIXME there should never be a server running if we are initializing the OLT
230 oltLogger.Fatal("OLT server already running.")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100231 }
232
233 // create new channel for processOltMessages Go routine
234 o.channel = make(chan Message)
235
236 o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
237 // FIXME we are assuming we have only one NNI
238 if o.Nnis[0] != nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800239 // NOTE we want to make sure the state is down when we initialize the OLT,
240 // the NNI may be in a bad state after a disable/reboot as we are not disabling it for
241 // in-band management
242 o.Nnis[0].OperState.SetState("down")
243 ch, handle, err := o.Nnis[0].NewVethChan()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100244 if err == nil {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800245 oltLogger.WithFields(log.Fields{
246 "Type": o.Nnis[0].Type,
247 "IntfId": o.Nnis[0].ID,
248 "OperState": o.Nnis[0].OperState.Current(),
249 }).Info("NNI Channel created")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100250 o.nniPktInChannel = ch
Matteo Scandolo401503a2019-12-11 14:48:14 -0800251 o.nniHandle = handle
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100252 } else {
Matteo Scandolo401503a2019-12-11 14:48:14 -0800253 oltLogger.Errorf("Error getting NNI channel: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100254 }
255 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700256}
257
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800258func (o *OltDevice) RestartOLT() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100259
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700260 softReboot := false
Matteo Scandolo4a036262020-08-17 15:56:13 -0700261 rebootDelay := common.Config.Olt.OltRebootDelay
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800262
263 oltLogger.WithFields(log.Fields{
264 "oltId": o.ID,
265 }).Infof("Simulating OLT restart... (%ds)", rebootDelay)
266
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700267 if o.InternalState.Is("enabled") {
268 oltLogger.WithFields(log.Fields{
269 "oltId": o.ID,
270 }).Info("This is an OLT soft reboot")
271 softReboot = true
272 }
273
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800274 // transition internal state to deleted
275 if err := o.InternalState.Event("delete"); err != nil {
276 oltLogger.WithFields(log.Fields{
277 "oltId": o.ID,
278 }).Errorf("Error deleting OLT: %v", err)
279 return err
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100280 }
281
282 // TODO handle hard poweroff (i.e. no indications sent to Voltha) vs soft poweroff
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800283 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
284 if err := o.StopOltServer(); err != nil {
Pragya Arya2225f202020-01-29 18:05:01 +0530285 oltLogger.Errorf("Error in stopping OLT server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100286 return err
287 }
288
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700289 if softReboot {
290 for _, pon := range o.Pons {
291 if pon.InternalState.Current() == "enabled" {
292 // disable PONs
293 msg := Message{
294 Type: PonIndication,
295 Data: PonIndicationMessage{
296 OperState: DOWN,
297 PonPortID: pon.ID,
298 },
299 }
300 o.channel <- msg
301 }
302
303 for _, onu := range pon.Onus {
304 _ = onu.InternalState.Event("disable")
305 }
306 }
307 } else {
308 // PONs are already handled in the Disable call
309 for _, pon := range olt.Pons {
310 // ONUs are not automatically disabled when a PON goes down
311 // as it's possible that it's an admin down and in that case the ONUs need to keep their state
312 for _, onu := range pon.Onus {
313 _ = onu.InternalState.Event("disable")
314 }
Pragya Arya2225f202020-01-29 18:05:01 +0530315 }
316 }
317
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100318 // terminate the OLT's processOltMessages go routine
319 close(o.channel)
320 // terminate the OLT's processNniPacketIns go routine
Andy Bavier421f4d52020-01-21 15:39:22 -0700321 go o.nniHandle.Close()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100322 close(o.nniPktInChannel)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100323
Zdravko Bozakov3ddb2452019-11-29 14:33:41 +0100324 time.Sleep(time.Duration(rebootDelay) * time.Second)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100325
326 if err := o.InternalState.Event("initialize"); err != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800327 oltLogger.WithFields(log.Fields{
328 "oltId": o.ID,
329 }).Errorf("Error initializing OLT: %v", err)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100330 return err
331 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800332 oltLogger.WithFields(log.Fields{
333 "oltId": o.ID,
334 }).Info("OLT restart completed")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100335 return nil
336}
337
338// newOltServer launches a new grpc server for OpenOLT
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800339func (o *OltDevice) newOltServer() (*grpc.Server, error) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700340 address := common.Config.BBSim.OpenOltAddress
Matteo Scandolo4747d292019-08-05 11:50:18 -0700341 lis, err := net.Listen("tcp", address)
342 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700343 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700344 }
345 grpcServer := grpc.NewServer()
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100346
Matteo Scandolo4747d292019-08-05 11:50:18 -0700347 openolt.RegisterOpenoltServer(grpcServer, o)
348
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100349 reflection.Register(grpcServer)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700350
Shrey Baid688b4242020-07-10 20:40:10 +0530351 go func() { _ = grpcServer.Serve(lis) }()
Zdravko Bozakov958d81c2019-12-13 22:09:48 +0100352 oltLogger.Debugf("OLT listening on %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700353
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100354 return grpcServer, nil
355}
356
357// StopOltServer stops the OpenOLT grpc server
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800358func (o *OltDevice) StopOltServer() error {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100359 // TODO handle poweroff vs graceful shutdown
360 if oltServer != nil {
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800361 oltLogger.WithFields(log.Fields{
362 "oltId": o.SerialNumber,
363 }).Warnf("Stopping OLT gRPC server")
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100364 oltServer.Stop()
365 oltServer = nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700366 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800367
Matteo Scandolo4747d292019-08-05 11:50:18 -0700368 return nil
369}
370
371// Device Methods
372
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100373// Enable implements the OpenOLT EnableIndicationServer functionality
Shrey Baid688b4242020-07-10 20:40:10 +0530374func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700375 oltLogger.Debug("Enable OLT called")
Pragya Arya2225f202020-01-29 18:05:01 +0530376 rebootFlag := false
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700377
David Bainbridge103cf022019-12-16 20:11:35 +0000378 // If enabled has already been called then an enabled context has
379 // been created. If this is the case then we want to cancel all the
380 // proessing loops associated with that enable before we recreate
381 // new ones
382 o.Lock()
383 if o.enableContext != nil && o.enableContextCancel != nil {
Matteo Scandolo635b2bf2020-09-04 10:23:40 -0700384 oltLogger.Info("This is an OLT reboot")
David Bainbridge103cf022019-12-16 20:11:35 +0000385 o.enableContextCancel()
Pragya Arya2225f202020-01-29 18:05:01 +0530386 rebootFlag = true
David Bainbridge103cf022019-12-16 20:11:35 +0000387 }
388 o.enableContext, o.enableContextCancel = context.WithCancel(context.TODO())
389 o.Unlock()
390
Matteo Scandolo4747d292019-08-05 11:50:18 -0700391 wg := sync.WaitGroup{}
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800392 wg.Add(3)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700393
Matteo Scandolo4a036262020-08-17 15:56:13 -0700394 o.OpenoltStream = stream
Pragya Arya1cbefa42020-01-13 12:15:29 +0530395
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100396 // create Go routine to process all OLT events
David Bainbridge103cf022019-12-16 20:11:35 +0000397 go o.processOltMessages(o.enableContext, stream, &wg)
398 go o.processNniPacketIns(o.enableContext, stream, &wg)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700399
400 // enable the OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100401 oltMsg := Message{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700402 Type: OltIndication,
403 Data: OltIndicationMessage{
404 OperState: UP,
405 },
406 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100407 o.channel <- oltMsg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700408
409 // send NNI Port Indications
410 for _, nni := range o.Nnis {
411 msg := Message{
412 Type: NniIndication,
413 Data: NniIndicationMessage{
414 OperState: UP,
415 NniPortID: nni.ID,
416 },
417 }
418 o.channel <- msg
419 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100420
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800421 go o.processOmciMessages(o.enableContext, stream, &wg)
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100422
Shrey Baid688b4242020-07-10 20:40:10 +0530423 if rebootFlag {
Pragya Arya2225f202020-01-29 18:05:01 +0530424 for _, pon := range o.Pons {
425 if pon.InternalState.Current() == "disabled" {
426 msg := Message{
427 Type: PonIndication,
428 Data: PonIndicationMessage{
429 OperState: UP,
430 PonPortID: pon.ID,
431 },
432 }
433 o.channel <- msg
Matteo Scandoloe60a5052020-02-07 00:31:14 +0000434 }
Pragya Arya2225f202020-01-29 18:05:01 +0530435 }
436 } else {
437
438 // 1. controlledActivation == Default: Send both PON and ONUs indications
439 // 2. controlledActivation == only-onu: that means only ONUs will be controlled activated, so auto send PON indications
440
441 if o.ControlledActivation == Default || o.ControlledActivation == OnlyONU {
442 // send PON Port indications
443 for _, pon := range o.Pons {
444 msg := Message{
445 Type: PonIndication,
446 Data: PonIndicationMessage{
447 OperState: UP,
448 PonPortID: pon.ID,
449 },
450 }
451 o.channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700452 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700453 }
454 }
455
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800456 oltLogger.Debug("Enable OLT Done")
Pragya Arya996a0892020-03-09 21:47:52 +0530457
458 if !o.enablePerf {
459 // Start a go routine to send periodic port stats to openolt adapter
460 go o.periodicPortStats(o.enableContext)
461 }
462
Matteo Scandolo4747d292019-08-05 11:50:18 -0700463 wg.Wait()
Matteo Scandolo4747d292019-08-05 11:50:18 -0700464}
465
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800466func (o *OltDevice) processOmciMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400467 ch := omcisim.GetChannel()
468
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100469 oltLogger.Debug("Starting OMCI Indication Channel")
William Kurkian9dadc5b2019-10-22 13:51:57 -0400470
David Bainbridge103cf022019-12-16 20:11:35 +0000471loop:
472 for {
473 select {
474 case <-ctx.Done():
475 oltLogger.Debug("OMCI processing canceled via context")
476 break loop
477 case message, ok := <-ch:
478 if !ok || ctx.Err() != nil {
479 oltLogger.Debug("OMCI processing canceled via channel close")
480 break loop
481 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800482
483 oltLogger.WithFields(log.Fields{
484 "messageType": message.Type,
485 "OnuId": message.Data.OnuId,
486 "IntfId": message.Data.IntfId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700487 }).Debug("Received message on OMCI Sim channel")
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800488
David Bainbridge103cf022019-12-16 20:11:35 +0000489 onuId := message.Data.OnuId
490 intfId := message.Data.IntfId
491 onu, err := o.FindOnuById(intfId, onuId)
492 if err != nil {
493 oltLogger.Errorf("Failed to find onu: %v", err)
494 continue
495 }
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800496 go onu.processOmciMessage(message, stream)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400497 }
William Kurkian9dadc5b2019-10-22 13:51:57 -0400498 }
David Bainbridge103cf022019-12-16 20:11:35 +0000499
500 wg.Done()
William Kurkian9dadc5b2019-10-22 13:51:57 -0400501}
502
Pragya Arya996a0892020-03-09 21:47:52 +0530503func (o *OltDevice) periodicPortStats(ctx context.Context) {
504 var portStats *openolt.PortStatistics
505 for {
506 select {
507 case <-time.After(time.Duration(o.PortStatsInterval) * time.Second):
508 // send NNI port stats
509 for _, port := range o.Nnis {
510 incrementStat := true
511 if port.OperState.Current() == "down" {
512 incrementStat = false
513 }
514 portStats, port.PacketCount = getPortStats(port.PacketCount, incrementStat)
515 o.sendPortStatsIndication(portStats, port.ID, port.Type)
516 }
517
518 // send PON port stats
519 for _, port := range o.Pons {
520 incrementStat := true
521 // do not increment port stats if PON port is down or no ONU is activated on PON port
522 if port.OperState.Current() == "down" || port.GetNumOfActiveOnus() < 1 {
523 incrementStat = false
524 }
525 portStats, port.PacketCount = getPortStats(port.PacketCount, incrementStat)
526 o.sendPortStatsIndication(portStats, port.ID, port.Type)
527 }
528 case <-ctx.Done():
529 log.Debug("Stop sending port stats")
530 return
531 }
532
533 }
534}
535
Matteo Scandolo4747d292019-08-05 11:50:18 -0700536// Helpers method
537
Shrey Baid688b4242020-07-10 20:40:10 +0530538func (o *OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700539 for _, pon := range o.Pons {
540 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700541 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700542 }
543 }
Shrey Baid688b4242020-07-10 20:40:10 +0530544 return nil, fmt.Errorf("Cannot find PonPort with id %d in OLT %d", id, o.ID)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700545}
546
Shrey Baid688b4242020-07-10 20:40:10 +0530547func (o *OltDevice) getNniById(id uint32) (*NniPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700548 for _, nni := range o.Nnis {
549 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700550 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700551 }
552 }
Shrey Baid688b4242020-07-10 20:40:10 +0530553 return nil, fmt.Errorf("Cannot find NniPort with id %d in OLT %d", id, o.ID)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700554}
555
Scott Baker41724b82020-01-21 19:54:53 -0800556func (o *OltDevice) sendAlarmIndication(alarmInd *openolt.AlarmIndication, stream openolt.Openolt_EnableIndicationServer) {
557 data := &openolt.Indication_AlarmInd{AlarmInd: alarmInd}
558 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
559 oltLogger.Errorf("Failed to send Alarm Indication: %v", err)
560 return
561 }
562
563 oltLogger.WithFields(log.Fields{
564 "AlarmIndication": alarmInd,
565 }).Debug("Sent Indication_AlarmInd")
566}
567
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100568func (o *OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700569 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
570 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700571 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800572 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700573 }
574
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700575 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700576 "OperState": msg.OperState,
577 }).Debug("Sent Indication_OltInd")
578}
579
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100580func (o *OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700581 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo401503a2019-12-11 14:48:14 -0800582 if msg.OperState == UP {
583 if err := nni.OperState.Event("enable"); err != nil {
584 log.WithFields(log.Fields{
585 "Type": nni.Type,
586 "IntfId": nni.ID,
587 "OperState": nni.OperState.Current(),
588 }).Errorf("Can't move NNI Port to enabled state: %v", err)
589 }
590 } else if msg.OperState == DOWN {
591 if err := nni.OperState.Event("disable"); err != nil {
592 log.WithFields(log.Fields{
593 "Type": nni.Type,
594 "IntfId": nni.ID,
595 "OperState": nni.OperState.Current(),
596 }).Errorf("Can't move NNI Port to disable state: %v", err)
597 }
598 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700599 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700600 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700601 Type: nni.Type,
602 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700603 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700604 }}
605
606 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700607 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800608 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700609 }
610
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700611 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700612 "Type": nni.Type,
613 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700614 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700615 }).Debug("Sent Indication_IntfOperInd for NNI")
616}
617
Pragya Arya2225f202020-01-29 18:05:01 +0530618func (o *OltDevice) sendPonIndication(ponPortID uint32) {
619
Matteo Scandolo4a036262020-08-17 15:56:13 -0700620 stream := o.OpenoltStream
Pragya Arya2225f202020-01-29 18:05:01 +0530621 pon, _ := o.GetPonById(ponPortID)
622 // Send IntfIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700623 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700624 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700625 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700626 }}
627
628 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700629 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800630 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700631 }
632
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700633 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700634 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700635 "OperState": pon.OperState.Current(),
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700636 }).Debug("Sent Indication_IntfInd for PON")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700637
Pragya Arya2225f202020-01-29 18:05:01 +0530638 // Send IntfOperIndication for PON port
Matteo Scandolo4747d292019-08-05 11:50:18 -0700639 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700640 Type: pon.Type,
641 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700642 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700643 }}
644
645 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700646 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo08badf42019-12-12 11:21:50 -0800647 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700648 }
649
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700650 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700651 "Type": pon.Type,
652 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700653 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700654 }).Debug("Sent Indication_IntfOperInd for PON")
655}
656
Pragya Arya996a0892020-03-09 21:47:52 +0530657func (o *OltDevice) sendPortStatsIndication(stats *openolt.PortStatistics, portID uint32, portType string) {
Shrey Baid55f328c2020-07-07 19:20:42 +0530658 if o.InternalState.Current() == "enabled" {
659 oltLogger.WithFields(log.Fields{
660 "Type": portType,
661 "IntfId": portID,
662 }).Trace("Sending port stats")
663 stats.IntfId = InterfaceIDToPortNo(portID, portType)
664 data := &openolt.Indication_PortStats{
665 PortStats: stats,
666 }
Matteo Scandolo4a036262020-08-17 15:56:13 -0700667 stream := o.OpenoltStream
Shrey Baid55f328c2020-07-07 19:20:42 +0530668 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
669 oltLogger.Errorf("Failed to send PortStats: %v", err)
670 return
671 }
Pragya Arya996a0892020-03-09 21:47:52 +0530672 }
673}
674
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100675// processOltMessages handles messages received over the OpenOLT interface
David Bainbridge103cf022019-12-16 20:11:35 +0000676func (o *OltDevice) processOltMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100677 oltLogger.Debug("Starting OLT Indication Channel")
David Bainbridge103cf022019-12-16 20:11:35 +0000678 ch := o.channel
Matteo Scandolo4747d292019-08-05 11:50:18 -0700679
David Bainbridge103cf022019-12-16 20:11:35 +0000680loop:
681 for {
682 select {
683 case <-ctx.Done():
684 oltLogger.Debug("OLT Indication processing canceled via context")
685 break loop
686 case message, ok := <-ch:
687 if !ok || ctx.Err() != nil {
688 oltLogger.Debug("OLT Indication processing canceled via closed channel")
689 break loop
Matteo Scandolo4747d292019-08-05 11:50:18 -0700690 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700691
David Bainbridge103cf022019-12-16 20:11:35 +0000692 oltLogger.WithFields(log.Fields{
693 "oltId": o.ID,
694 "messageType": message.Type,
695 }).Trace("Received message")
696
697 switch message.Type {
698 case OltIndication:
699 msg, _ := message.Data.(OltIndicationMessage)
700 if msg.OperState == UP {
Shrey Baid688b4242020-07-10 20:40:10 +0530701 _ = o.InternalState.Event("enable")
702 _ = o.OperState.Event("enable")
David Bainbridge103cf022019-12-16 20:11:35 +0000703 } else if msg.OperState == DOWN {
Shrey Baid688b4242020-07-10 20:40:10 +0530704 _ = o.InternalState.Event("disable")
705 _ = o.OperState.Event("disable")
David Bainbridge103cf022019-12-16 20:11:35 +0000706 }
707 o.sendOltIndication(msg, stream)
Scott Baker41724b82020-01-21 19:54:53 -0800708 case AlarmIndication:
709 alarmInd, _ := message.Data.(*openolt.AlarmIndication)
710 o.sendAlarmIndication(alarmInd, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000711 case NniIndication:
712 msg, _ := message.Data.(NniIndicationMessage)
713 o.sendNniIndication(msg, stream)
714 case PonIndication:
715 msg, _ := message.Data.(PonIndicationMessage)
Pragya Arya2225f202020-01-29 18:05:01 +0530716 pon, _ := o.GetPonById(msg.PonPortID)
717 if msg.OperState == UP {
Hardik Windlassad790cb2020-06-17 21:26:22 +0530718 if err := pon.OperState.Event("enable"); err != nil {
719 oltLogger.WithFields(log.Fields{
720 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800721 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530722 }).Error("Can't Enable Oper state for PON Port")
723 }
724 if err := pon.InternalState.Event("enable"); err != nil {
725 oltLogger.WithFields(log.Fields{
726 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800727 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530728 }).Error("Can't Enable Internal state for PON Port")
729 }
Pragya Arya2225f202020-01-29 18:05:01 +0530730 } else if msg.OperState == DOWN {
Hardik Windlassad790cb2020-06-17 21:26:22 +0530731 if err := pon.OperState.Event("disable"); err != nil {
732 oltLogger.WithFields(log.Fields{
733 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800734 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530735 }).Error("Can't Disable Oper state for PON Port")
736 }
737 if err := pon.InternalState.Event("disable"); err != nil {
738 oltLogger.WithFields(log.Fields{
739 "IntfId": msg.PonPortID,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800740 "Err": err,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530741 }).Error("Can't Disable Internal state for PON Port")
742 }
Pragya Arya2225f202020-01-29 18:05:01 +0530743 }
David Bainbridge103cf022019-12-16 20:11:35 +0000744 default:
745 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
746 }
747 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700748 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100749 wg.Done()
750 oltLogger.Warn("Stopped handling OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700751}
752
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100753// processNniPacketIns handles messages received over the NNI interface
David Bainbridge103cf022019-12-16 20:11:35 +0000754func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700755 oltLogger.WithFields(log.Fields{
756 "nniChannel": o.nniPktInChannel,
Matteo Scandolo401503a2019-12-11 14:48:14 -0800757 }).Debug("Started Processing Packets arriving from the NNI")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700758 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700759
David Bainbridge103cf022019-12-16 20:11:35 +0000760 ch := o.nniPktInChannel
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700761
David Bainbridge103cf022019-12-16 20:11:35 +0000762loop:
763 for {
764 select {
765 case <-ctx.Done():
766 oltLogger.Debug("NNI Indication processing canceled via context")
767 break loop
768 case message, ok := <-ch:
769 if !ok || ctx.Err() != nil {
770 oltLogger.Debug("NNI Indication processing canceled via channel closed")
771 break loop
772 }
773 oltLogger.Tracef("Received packets on NNI Channel")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700774
David Bainbridge103cf022019-12-16 20:11:35 +0000775 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700776
David Bainbridge103cf022019-12-16 20:11:35 +0000777 if err != nil {
778 log.WithFields(log.Fields{
779 "IntfType": "nni",
780 "IntfId": nniId,
781 "Pkt": message.Pkt.Data(),
782 }).Error("Can't find Dst MacAddress in packet")
783 return
784 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700785
Matteo Scandolo4a036262020-08-17 15:56:13 -0700786 s, err := o.FindServiceByMacAddress(onuMac)
David Bainbridge103cf022019-12-16 20:11:35 +0000787 if err != nil {
788 log.WithFields(log.Fields{
789 "IntfType": "nni",
790 "IntfId": nniId,
791 "Pkt": message.Pkt.Data(),
792 "MacAddress": onuMac.String(),
793 }).Error("Can't find ONU with MacAddress")
794 return
795 }
796
Matteo Scandolo4a036262020-08-17 15:56:13 -0700797 service := s.(*Service)
798
Matteo Scandolo8d281372020-09-03 16:23:37 -0700799 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(service.STag, service.CTag, message.Pkt, service.UsPonCTagPriority)
David Bainbridge103cf022019-12-16 20:11:35 +0000800 if err != nil {
801 log.Error("Fail to add double tag to packet")
802 }
803
804 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
805 IntfType: "nni",
806 IntfId: nniId,
807 Pkt: doubleTaggedPkt.Data()}}
808 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
809 oltLogger.WithFields(log.Fields{
810 "IntfType": data.PktInd.IntfType,
811 "IntfId": nniId,
812 "Pkt": doubleTaggedPkt.Data(),
813 }).Errorf("Fail to send PktInd indication: %v", err)
814 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700815 oltLogger.WithFields(log.Fields{
816 "IntfType": data.PktInd.IntfType,
817 "IntfId": nniId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700818 "Pkt": hex.EncodeToString(doubleTaggedPkt.Data()),
819 "OnuSn": service.Onu.Sn(),
820 }).Trace("Sent PktInd indication (from NNI to VOLTHA)")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700821 }
822 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100823 wg.Done()
824 oltLogger.WithFields(log.Fields{
825 "nniChannel": o.nniPktInChannel,
826 }).Warn("Stopped handling NNI Channel")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700827}
828
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700829// returns an ONU with a given Serial Number
Shrey Baid688b4242020-07-10 20:40:10 +0530830func (o *OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200831 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700832 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700833 for _, pon := range o.Pons {
834 for _, onu := range pon.Onus {
835 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700836 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700837 }
838 }
839 }
840
Shrey Baid688b4242020-07-10 20:40:10 +0530841 return &Onu{}, fmt.Errorf("cannot-find-onu-by-serial-number-%s", serialNumber)
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700842}
843
William Kurkian9dadc5b2019-10-22 13:51:57 -0400844// returns an ONU with a given interface/Onu Id
Shrey Baid688b4242020-07-10 20:40:10 +0530845func (o *OltDevice) FindOnuById(intfId uint32, onuId uint32) (*Onu, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200846 // TODO this function can be a performance bottleneck when we have many ONUs,
William Kurkian9dadc5b2019-10-22 13:51:57 -0400847 // memoizing it will remove the bottleneck
848 for _, pon := range o.Pons {
849 if pon.ID == intfId {
850 for _, onu := range pon.Onus {
851 if onu.ID == onuId {
852 return onu, nil
853 }
854 }
855 }
856 }
Shrey Baid688b4242020-07-10 20:40:10 +0530857 return &Onu{}, fmt.Errorf("cannot-find-onu-by-id-%v-%v", intfId, onuId)
William Kurkian9dadc5b2019-10-22 13:51:57 -0400858}
859
Matteo Scandolo4a036262020-08-17 15:56:13 -0700860// returns a Service with a given Mac Address
861func (o *OltDevice) FindServiceByMacAddress(mac net.HardwareAddr) (ServiceIf, error) {
Zdravko Bozakov2da76342019-10-21 09:47:35 +0200862 // TODO this function can be a performance bottleneck when we have many ONUs,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700863 // memoizing it will remove the bottleneck
864 for _, pon := range o.Pons {
865 for _, onu := range pon.Onus {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700866 s, err := onu.findServiceByMacAddress(mac)
867 if err == nil {
868 return s, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700869 }
870 }
871 }
872
Matteo Scandolo4a036262020-08-17 15:56:13 -0700873 return nil, fmt.Errorf("cannot-find-service-by-mac-address-%s", mac)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700874}
875
Matteo Scandolo4747d292019-08-05 11:50:18 -0700876// GRPC Endpoints
877
Shrey Baid688b4242020-07-10 20:40:10 +0530878func (o *OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700879 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700880 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700881 }).Info("Received ActivateOnu call from VOLTHA")
Pragya Arya324337e2020-02-20 14:35:08 +0530882 publishEvent("ONU-activate-indication-received", int32(onu.IntfId), int32(onu.OnuId), onuSnToString(onu.SerialNumber))
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700883
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700884 pon, _ := o.GetPonById(onu.IntfId)
885 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
William Kurkian0418bc82019-11-06 12:16:24 -0500886 _onu.SetID(onu.OnuId)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700887
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700888 if err := _onu.OperState.Event("enable"); err != nil {
889 oltLogger.WithFields(log.Fields{
890 "IntfId": _onu.PonPortID,
891 "OnuSn": _onu.Sn(),
892 "OnuId": _onu.ID,
893 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700894 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700895 if err := _onu.InternalState.Event("enable"); err != nil {
896 oltLogger.WithFields(log.Fields{
897 "IntfId": _onu.PonPortID,
898 "OnuSn": _onu.Sn(),
899 "OnuId": _onu.ID,
900 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
901 }
902
903 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
904
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700905 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700906}
907
Shrey Baid688b4242020-07-10 20:40:10 +0530908func (o *OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700909 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700910 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700911}
912
Shrey Baid688b4242020-07-10 20:40:10 +0530913func (o *OltDevice) DeleteOnu(_ context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Pragya Arya1cbefa42020-01-13 12:15:29 +0530914 oltLogger.WithFields(log.Fields{
915 "IntfId": onu.IntfId,
916 "OnuId": onu.OnuId,
917 }).Info("Received DeleteOnu call from VOLTHA")
918
919 pon, err := o.GetPonById(onu.IntfId)
920 if err != nil {
921 oltLogger.WithFields(log.Fields{
922 "OnuId": onu.OnuId,
923 "IntfId": onu.IntfId,
924 "err": err,
925 }).Error("Can't find PonPort")
926 }
927 _onu, err := pon.GetOnuById(onu.OnuId)
928 if err != nil {
929 oltLogger.WithFields(log.Fields{
930 "OnuId": onu.OnuId,
931 "IntfId": onu.IntfId,
932 "err": err,
933 }).Error("Can't find Onu")
934 }
935
Hardik Windlassad790cb2020-06-17 21:26:22 +0530936 if err := _onu.InternalState.Event("disable"); err != nil {
Pragya Arya1cbefa42020-01-13 12:15:29 +0530937 oltLogger.WithFields(log.Fields{
938 "IntfId": _onu.PonPortID,
939 "OnuSn": _onu.Sn(),
940 "OnuId": _onu.ID,
Hardik Windlassad790cb2020-06-17 21:26:22 +0530941 }).Infof("Failed to transition ONU to disabled state: %s", err.Error())
942 }
943
Hardik Windlassad790cb2020-06-17 21:26:22 +0530944 // ONU Re-Discovery
945 if o.InternalState.Current() == "enabled" && pon.InternalState.Current() == "enabled" {
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530946 go _onu.ReDiscoverOnu()
Pragya Arya1cbefa42020-01-13 12:15:29 +0530947 }
948
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700949 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700950}
951
Shrey Baid688b4242020-07-10 20:40:10 +0530952func (o *OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700953 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800954 oltLogger.WithFields(log.Fields{
955 "oltId": o.ID,
956 }).Info("Disabling OLT")
Pragya Arya324337e2020-02-20 14:35:08 +0530957 publishEvent("OLT-disable-received", -1, -1, "")
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800958
Matteo Scandolo401503a2019-12-11 14:48:14 -0800959 for _, pon := range o.Pons {
Pragya Arya2225f202020-01-29 18:05:01 +0530960 if pon.InternalState.Current() == "enabled" {
961 // disable PONs
962 msg := Message{
963 Type: PonIndication,
964 Data: PonIndicationMessage{
965 OperState: DOWN,
966 PonPortID: pon.ID,
967 },
968 }
969 o.channel <- msg
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800970 }
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800971 }
972
Matteo Scandolo401503a2019-12-11 14:48:14 -0800973 // Note that we are not disabling the NNI as the real OLT does not.
974 // The reason for that is in-band management
Matteo Scandolod02b79b2019-12-05 16:42:13 -0800975
976 // disable OLT
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100977 oltMsg := Message{
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700978 Type: OltIndication,
979 Data: OltIndicationMessage{
980 OperState: DOWN,
981 },
982 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100983 o.channel <- oltMsg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700984 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700985}
986
Shrey Baid688b4242020-07-10 20:40:10 +0530987func (o *OltDevice) DisablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
Hardik Windlassad790cb2020-06-17 21:26:22 +0530988 oltLogger.Infof("DisablePonIf request received for PON %d", intf.IntfId)
Andrea Campanella340b9ea2020-04-28 18:34:01 +0200989 ponID := intf.GetIntfId()
990 pon, _ := o.GetPonById(intf.IntfId)
Andrea Campanella340b9ea2020-04-28 18:34:01 +0200991
992 msg := Message{
993 Type: PonIndication,
994 Data: PonIndicationMessage{
995 OperState: DOWN,
996 PonPortID: ponID,
997 },
998 }
999 o.channel <- msg
1000
1001 for _, onu := range pon.Onus {
1002
1003 onuIndication := OnuIndicationMessage{
1004 OperState: DOWN,
1005 PonPortID: ponID,
1006 OnuID: onu.ID,
1007 OnuSN: onu.SerialNumber,
1008 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001009 onu.sendOnuIndication(onuIndication, o.OpenoltStream)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001010
1011 }
1012
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001013 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001014}
1015
Zdravko Bozakov681364d2019-11-10 14:28:46 +01001016func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001017 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Pragya Arya324337e2020-02-20 14:35:08 +05301018 publishEvent("OLT-enable-received", -1, -1, "")
Matteo Scandolo4747d292019-08-05 11:50:18 -07001019 o.Enable(stream)
1020 return nil
1021}
1022
Shrey Baid688b4242020-07-10 20:40:10 +05301023func (o *OltDevice) EnablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
Hardik Windlassad790cb2020-06-17 21:26:22 +05301024 oltLogger.Infof("EnablePonIf request received for PON %d", intf.IntfId)
Pragya Arya2225f202020-01-29 18:05:01 +05301025 ponID := intf.GetIntfId()
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001026 pon, _ := o.GetPonById(intf.IntfId)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001027
Pragya Arya2225f202020-01-29 18:05:01 +05301028 msg := Message{
1029 Type: PonIndication,
1030 Data: PonIndicationMessage{
1031 OperState: UP,
1032 PonPortID: ponID,
1033 },
1034 }
1035 o.channel <- msg
1036
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001037 for _, onu := range pon.Onus {
1038
1039 onuIndication := OnuIndicationMessage{
1040 OperState: UP,
1041 PonPortID: ponID,
1042 OnuID: onu.ID,
1043 OnuSN: onu.SerialNumber,
1044 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001045 onu.sendOnuIndication(onuIndication, o.OpenoltStream)
Andrea Campanella340b9ea2020-04-28 18:34:01 +02001046
1047 }
1048
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001049 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001050}
1051
Shrey Baid688b4242020-07-10 20:40:10 +05301052func (o *OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001053 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001054 "IntfId": flow.AccessIntfId,
1055 "OnuId": flow.OnuId,
1056 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001057 "InnerVlan": flow.Classifier.IVid,
1058 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001059 "FlowType": flow.FlowType,
1060 "FlowId": flow.FlowId,
1061 "UniID": flow.UniId,
1062 "PortNo": flow.PortNo,
Pragya Arya8bdb4532020-03-02 17:08:09 +05301063 }).Tracef("OLT receives FlowAdd")
1064
1065 flowKey := FlowKey{}
1066 if !o.enablePerf {
1067 flowKey = FlowKey{ID: flow.FlowId, Direction: flow.FlowType}
1068 olt.Flows[flowKey] = *flow
1069 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001070
1071 if flow.AccessIntfId == -1 {
1072 oltLogger.WithFields(log.Fields{
1073 "FlowId": flow.FlowId,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001074 }).Debug("Adding OLT flow")
Jonathan Hartb5fc46a2020-03-31 16:42:31 -07001075 } else if flow.FlowType == "multicast" {
1076 oltLogger.WithFields(log.Fields{
1077 "FlowId": flow.FlowId,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001078 }).Debug("Adding OLT multicast flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001079 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001080 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -07001081 if err != nil {
1082 oltLogger.WithFields(log.Fields{
1083 "OnuId": flow.OnuId,
1084 "IntfId": flow.AccessIntfId,
1085 "err": err,
1086 }).Error("Can't find PonPort")
1087 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001088 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -07001089 if err != nil {
1090 oltLogger.WithFields(log.Fields{
1091 "OnuId": flow.OnuId,
1092 "IntfId": flow.AccessIntfId,
1093 "err": err,
1094 }).Error("Can't find Onu")
Jonathan Hartb5fc46a2020-03-31 16:42:31 -07001095 return nil, err
Matteo Scandolo27428702019-10-11 16:21:16 -07001096 }
Pragya Arya8bdb4532020-03-02 17:08:09 +05301097 if !o.enablePerf {
1098 onu.Flows = append(onu.Flows, flowKey)
Pragya Arya1d5ffb82020-03-20 18:51:37 +05301099 // Generate event on first flow for ONU
1100 if len(onu.Flows) == 1 {
1101 publishEvent("Flow-add-received", int32(onu.PonPortID), int32(onu.ID), onuSnToString(onu.SerialNumber))
1102 }
Pragya Arya8bdb4532020-03-02 17:08:09 +05301103 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001104
1105 msg := Message{
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001106 Type: FlowAdd,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001107 Data: OnuFlowUpdateMessage{
1108 PonPortID: pon.ID,
1109 OnuID: onu.ID,
1110 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001111 },
1112 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001113 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -07001114 }
1115
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001116 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001117}
1118
Pragya Arya8bdb4532020-03-02 17:08:09 +05301119// FlowRemove request from VOLTHA
Shrey Baid688b4242020-07-10 20:40:10 +05301120func (o *OltDevice) FlowRemove(_ context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001121
Pragya Arya8bdb4532020-03-02 17:08:09 +05301122 oltLogger.WithFields(log.Fields{
Shrey Baid55f328c2020-07-07 19:20:42 +05301123 "FlowId": flow.FlowId,
1124 "FlowType": flow.FlowType,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001125 }).Debug("OLT receives FlowRemove")
Pragya Arya8bdb4532020-03-02 17:08:09 +05301126
1127 if !o.enablePerf { // remove only if flow were stored
1128 flowKey := FlowKey{
1129 ID: flow.FlowId,
1130 Direction: flow.FlowType,
1131 }
1132
1133 // Check if flow exists
1134 storedFlow, ok := o.Flows[flowKey]
1135 if !ok {
1136 oltLogger.Errorf("Flow %v not found", flow)
1137 return new(openolt.Empty), status.Errorf(codes.NotFound, "Flow not found")
1138 }
1139
1140 // if its ONU flow remove it from ONU also
1141 if storedFlow.AccessIntfId != -1 {
1142 pon := o.Pons[uint32(storedFlow.AccessIntfId)]
1143 onu, err := pon.GetOnuById(uint32(storedFlow.OnuId))
1144 if err != nil {
1145 oltLogger.WithFields(log.Fields{
1146 "OnuId": storedFlow.OnuId,
1147 "IntfId": storedFlow.AccessIntfId,
1148 "err": err,
1149 }).Error("ONU not found")
1150 return new(openolt.Empty), nil
1151 }
1152 onu.DeleteFlow(flowKey)
Pragya Arya1d5ffb82020-03-20 18:51:37 +05301153 publishEvent("Flow-remove-received", int32(onu.PonPortID), int32(onu.ID), onuSnToString(onu.SerialNumber))
Pragya Arya8bdb4532020-03-02 17:08:09 +05301154 }
1155
1156 // delete from olt flows
1157 delete(o.Flows, flowKey)
1158 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001159
1160 if flow.AccessIntfId == -1 {
1161 oltLogger.WithFields(log.Fields{
1162 "FlowId": flow.FlowId,
1163 }).Debug("Removing OLT flow")
1164 } else if flow.FlowType == "multicast" {
1165 oltLogger.WithFields(log.Fields{
1166 "FlowId": flow.FlowId,
1167 }).Debug("Removing OLT multicast flow")
1168 } else {
1169
1170 onu, err := o.GetOnuByFlowId(flow.FlowId)
1171 if err != nil {
1172 oltLogger.WithFields(log.Fields{
1173 "OnuId": flow.OnuId,
1174 "IntfId": flow.AccessIntfId,
1175 "err": err,
1176 }).Error("Can't find Onu")
1177 return nil, err
1178 }
1179
1180 msg := Message{
1181 Type: FlowRemoved,
1182 Data: OnuFlowUpdateMessage{
Shrey Baid55f328c2020-07-07 19:20:42 +05301183 Flow: flow,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001184 },
1185 }
1186 onu.Channel <- msg
1187 }
1188
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001189 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001190}
1191
Shrey Baid688b4242020-07-10 20:40:10 +05301192func (o *OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo18859852020-01-15 13:33:57 -08001193 res := openolt.Heartbeat{HeartbeatSignature: uint32(time.Now().Unix())}
1194 oltLogger.WithFields(log.Fields{
1195 "signature": res.HeartbeatSignature,
1196 }).Trace("HeartbeatCheck")
1197 return &res, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001198}
1199
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001200func (o *OltDevice) GetOnuByFlowId(flowId uint32) (*Onu, error) {
1201 for _, pon := range o.Pons {
1202 for _, onu := range pon.Onus {
1203 for _, fId := range onu.FlowIds {
1204 if fId == flowId {
1205 return onu, nil
1206 }
1207 }
1208 }
1209 }
Shrey Baid688b4242020-07-10 20:40:10 +05301210 return nil, fmt.Errorf("Cannot find Onu by flowId %d", flowId)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -07001211}
1212
Shrey Baid688b4242020-07-10 20:40:10 +05301213func (o *OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -07001214
Matteo Scandoloda9cbe22019-08-19 16:05:10 -07001215 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001216 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -07001217 "PonPorts": o.NumPon,
1218 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -07001219 devinfo := new(openolt.DeviceInfo)
Matteo Scandolo4a036262020-08-17 15:56:13 -07001220 devinfo.Vendor = common.Config.Olt.Vendor
1221 devinfo.Model = common.Config.Olt.Model
1222 devinfo.HardwareVersion = common.Config.Olt.HardwareVersion
1223 devinfo.FirmwareVersion = common.Config.Olt.FirmwareVersion
1224 devinfo.Technology = common.Config.Olt.Technology
Matteo Scandoloda9cbe22019-08-19 16:05:10 -07001225 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -07001226 devinfo.OnuIdStart = 1
1227 devinfo.OnuIdEnd = 255
1228 devinfo.AllocIdStart = 1024
1229 devinfo.AllocIdEnd = 16383
1230 devinfo.GemportIdStart = 1024
1231 devinfo.GemportIdEnd = 65535
1232 devinfo.FlowIdStart = 1
1233 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -07001234 devinfo.DeviceSerialNumber = o.SerialNumber
Matteo Scandolo4a036262020-08-17 15:56:13 -07001235 devinfo.DeviceId = common.Config.Olt.DeviceId
Matteo Scandolo4747d292019-08-05 11:50:18 -07001236
1237 return devinfo, nil
1238}
1239
Shrey Baid688b4242020-07-10 20:40:10 +05301240func (o *OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Jonathan Hartacfa20e2020-03-31 15:20:14 -07001241 pon, err := o.GetPonById(omci_msg.IntfId)
1242 if err != nil {
1243 oltLogger.WithFields(log.Fields{
Matteo Scandolof65e6872020-04-15 15:18:43 -07001244 "error": err,
Jonathan Hartacfa20e2020-03-31 15:20:14 -07001245 "onu_id": omci_msg.OnuId,
1246 "pon_id": omci_msg.IntfId,
1247 }).Error("pon ID not found")
1248 return nil, err
1249 }
1250
1251 onu, err := pon.GetOnuById(omci_msg.OnuId)
1252 if err != nil {
1253 oltLogger.WithFields(log.Fields{
Matteo Scandolof65e6872020-04-15 15:18:43 -07001254 "error": err,
Jonathan Hartacfa20e2020-03-31 15:20:14 -07001255 "onu_id": omci_msg.OnuId,
1256 "pon_id": omci_msg.IntfId,
1257 }).Error("onu ID not found")
1258 return nil, err
1259 }
1260
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001261 oltLogger.WithFields(log.Fields{
1262 "IntfId": onu.PonPortID,
1263 "OnuId": onu.ID,
1264 "OnuSn": onu.Sn(),
1265 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001266 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001267 Type: OMCI,
1268 Data: OmciMessage{
1269 OnuSN: onu.SerialNumber,
1270 OnuID: onu.ID,
1271 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001272 },
1273 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -07001274 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001275 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001276}
1277
Shrey Baid688b4242020-07-10 20:40:10 +05301278func (o *OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001279 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -07001280 if err != nil {
1281 oltLogger.WithFields(log.Fields{
1282 "OnuId": onuPkt.OnuId,
1283 "IntfId": onuPkt.IntfId,
1284 "err": err,
1285 }).Error("Can't find PonPort")
1286 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001287 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -07001288 if err != nil {
1289 oltLogger.WithFields(log.Fields{
1290 "OnuId": onuPkt.OnuId,
1291 "IntfId": onuPkt.IntfId,
1292 "err": err,
1293 }).Error("Can't find Onu")
1294 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001295
Matteo Scandolo075b1892019-10-07 12:11:07 -07001296 oltLogger.WithFields(log.Fields{
1297 "IntfId": onu.PonPortID,
1298 "OnuId": onu.ID,
1299 "OnuSn": onu.Sn(),
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001300 "Packet": hex.EncodeToString(onuPkt.Pkt),
Matteo Scandolo75ed5b92020-09-03 09:03:16 -07001301 }).Trace("Received OnuPacketOut")
Matteo Scandolo075b1892019-10-07 12:11:07 -07001302
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001303 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001304 pktType, err := packetHandlers.IsEapolOrDhcp(rawpkt)
1305 if err != nil {
1306 onuLogger.WithFields(log.Fields{
1307 "IntfId": onu.PonPortID,
1308 "OnuId": onu.ID,
1309 "OnuSn": onu.Sn(),
1310 "Pkt": rawpkt.Data(),
1311 }).Error("Can't find pktType in packet, droppint it")
1312 return new(openolt.Empty), nil
1313 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001314
Matteo Scandolo4a036262020-08-17 15:56:13 -07001315 pktMac, err := packetHandlers.GetDstMacAddressFromPacket(rawpkt)
Matteo Scandolo4a036262020-08-17 15:56:13 -07001316 if err != nil {
Matteo Scandoloadc72a82020-09-08 18:46:08 -07001317 onuLogger.WithFields(log.Fields{
Matteo Scandolo4a036262020-08-17 15:56:13 -07001318 "IntfId": onu.PonPortID,
1319 "OnuId": onu.ID,
1320 "OnuSn": onu.Sn(),
1321 "Pkt": rawpkt.Data(),
1322 }).Error("Can't find Dst MacAddress in packet, droppint it")
1323 return new(openolt.Empty), nil
1324 }
1325
Matteo Scandolo075b1892019-10-07 12:11:07 -07001326 msg := Message{
1327 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001328 Data: OnuPacketMessage{
Matteo Scandolo4a036262020-08-17 15:56:13 -07001329 IntfId: onuPkt.IntfId,
1330 OnuId: onuPkt.OnuId,
1331 Packet: rawpkt,
1332 Type: pktType,
1333 MacAddress: pktMac,
Matteo Scandolo075b1892019-10-07 12:11:07 -07001334 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001335 }
Matteo Scandolo4a036262020-08-17 15:56:13 -07001336
Matteo Scandolo075b1892019-10-07 12:11:07 -07001337 onu.Channel <- msg
1338
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001339 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001340}
1341
Shrey Baid688b4242020-07-10 20:40:10 +05301342func (o *OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo635b2bf2020-09-04 10:23:40 -07001343
1344 // OLT Reboot is called in two cases:
1345 // - when an OLT is being removed (voltctl device disable -> voltctl device delete are called, then a new voltctl device create -> voltctl device enable will be issued)
1346 // - when an OLT needs to be rebooted (voltcl device reboot)
1347
Matteo Scandolod02b79b2019-12-05 16:42:13 -08001348 oltLogger.WithFields(log.Fields{
1349 "oltId": o.ID,
1350 }).Info("Shutting down")
Pragya Arya324337e2020-02-20 14:35:08 +05301351 publishEvent("OLT-reboot-received", -1, -1, "")
Shrey Baid688b4242020-07-10 20:40:10 +05301352 go func() { _ = o.RestartOLT() }()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001353 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001354}
1355
Shrey Baid688b4242020-07-10 20:40:10 +05301356func (o *OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Pragya Arya6a708d62020-01-01 17:17:20 +05301357 oltLogger.WithFields(log.Fields{
1358 "oltId": o.ID,
1359 }).Info("Received ReenableOlt request from VOLTHA")
Pragya Arya324337e2020-02-20 14:35:08 +05301360 publishEvent("OLT-reenable-received", -1, -1, "")
Pragya Arya6a708d62020-01-01 17:17:20 +05301361
Pragya Arya2225f202020-01-29 18:05:01 +05301362 // enable OLT
1363 oltMsg := Message{
1364 Type: OltIndication,
1365 Data: OltIndicationMessage{
1366 OperState: UP,
1367 },
Pragya Arya1881df02020-01-29 18:05:01 +05301368 }
Pragya Arya2225f202020-01-29 18:05:01 +05301369 o.channel <- oltMsg
Pragya Arya6a708d62020-01-01 17:17:20 +05301370
Pragya Arya2225f202020-01-29 18:05:01 +05301371 for _, pon := range o.Pons {
1372 if pon.InternalState.Current() == "disabled" {
1373 msg := Message{
1374 Type: PonIndication,
1375 Data: PonIndicationMessage{
1376 OperState: UP,
1377 PonPortID: pon.ID,
1378 },
1379 }
1380 o.channel <- msg
1381 }
1382 }
Matteo Scandoloe60a5052020-02-07 00:31:14 +00001383
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001384 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001385}
1386
Shrey Baid688b4242020-07-10 20:40:10 +05301387func (o *OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001388 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
1389
Shrey Baid688b4242020-07-10 20:40:10 +05301390 _ = o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001391 // NOTE should we return an error if sendNniPakcet fails?
1392 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001393}
1394
Shrey Baid688b4242020-07-10 20:40:10 +05301395func (o *OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001396 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001397 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001398}
1399
Shrey Baid688b4242020-07-10 20:40:10 +05301400func (o *OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001401 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001402 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -07001403}
1404
Shrey Baid688b4242020-07-10 20:40:10 +05301405func (o *OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -07001406 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001407 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -07001408}
1409
Shrey Baid688b4242020-07-10 20:40:10 +05301410func (s *OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001411 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001412 return new(openolt.Empty), nil
1413}
1414
Shrey Baid688b4242020-07-10 20:40:10 +05301415func (s *OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -07001416 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -07001417 return new(openolt.Empty), nil
1418}
1419
Shrey Baid688b4242020-07-10 20:40:10 +05301420func (s *OltDevice) CreateTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Anand S Katti09541352020-01-29 15:54:01 +05301421 oltLogger.WithFields(log.Fields{
1422 "OnuId": trafficSchedulers.OnuId,
1423 "IntfId": trafficSchedulers.IntfId,
1424 "OnuPortNo": trafficSchedulers.PortNo,
1425 }).Info("received CreateTrafficSchedulers")
1426
1427 if !s.enablePerf {
1428 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1429 if err != nil {
1430 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1431 return new(openolt.Empty), err
1432 }
1433 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1434 if err != nil {
1435 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1436 return new(openolt.Empty), err
1437 }
1438 onu.TrafficSchedulers = trafficSchedulers
1439 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001440 return new(openolt.Empty), nil
1441}
1442
Shrey Baid688b4242020-07-10 20:40:10 +05301443func (s *OltDevice) RemoveTrafficSchedulers(context context.Context, trafficSchedulers *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Anand S Katti09541352020-01-29 15:54:01 +05301444 oltLogger.WithFields(log.Fields{
1445 "OnuId": trafficSchedulers.OnuId,
1446 "IntfId": trafficSchedulers.IntfId,
1447 "OnuPortNo": trafficSchedulers.PortNo,
1448 }).Info("received RemoveTrafficSchedulers")
1449 if !s.enablePerf {
1450 pon, err := s.GetPonById(trafficSchedulers.IntfId)
1451 if err != nil {
1452 oltLogger.Errorf("Error retrieving PON by IntfId: %v", err)
1453 return new(openolt.Empty), err
1454 }
1455 onu, err := pon.GetOnuById(trafficSchedulers.OnuId)
1456 if err != nil {
1457 oltLogger.Errorf("Error retrieving ONU from pon by OnuId: %v", err)
1458 return new(openolt.Empty), err
1459 }
1460
1461 onu.TrafficSchedulers = nil
1462 }
Matteo Scandolod54283a2019-08-13 16:22:31 -07001463 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -07001464}
Scott Baker41724b82020-01-21 19:54:53 -08001465
1466// assumes caller has properly formulated an openolt.AlarmIndication
Shrey Baid688b4242020-07-10 20:40:10 +05301467func (o *OltDevice) SendAlarmIndication(context context.Context, ind *openolt.AlarmIndication) error {
Scott Baker41724b82020-01-21 19:54:53 -08001468 msg := Message{
1469 Type: AlarmIndication,
1470 Data: ind,
1471 }
1472
1473 o.channel <- msg
1474 return nil
1475}