blob: c3a62ff27e73305a532a129a296a2f54290abb47 [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 Scandolo47e69bb2019-08-28 15:41:12 -070023 "github.com/google/gopacket"
24 "github.com/google/gopacket/layers"
Matteo Scandolo4747d292019-08-05 11:50:18 -070025 "github.com/looplab/fsm"
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -070026 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070027 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070028 "github.com/opencord/voltha-protos/go/openolt"
Matteo Scandolod54283a2019-08-13 16:22:31 -070029 "github.com/opencord/voltha-protos/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070030 log "github.com/sirupsen/logrus"
31 "google.golang.org/grpc"
32 "net"
33 "sync"
34)
35
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070036var oltLogger = log.WithFields(log.Fields{
Matteo Scandolo84f7d482019-08-08 19:00:47 -070037 "module": "OLT",
38})
39
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070040type OltDevice struct {
41 // BBSIM Internals
42 ID int
43 SerialNumber string
44 NumNni int
45 NumPon int
46 NumOnuPerPon int
47 InternalState *fsm.FSM
48 channel chan Message
49 oltDoneChannel *chan bool
50 apiDoneChannel *chan bool
51 nniPktInChannel chan *bbsim.PacketMsg
52
Matteo Scandolo27428702019-10-11 16:21:16 -070053 Pons []*PonPort
54 Nnis []*NniPort
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070055
56 // OLT Attributes
57 OperState *fsm.FSM
Matteo Scandolo4747d292019-08-05 11:50:18 -070058}
59
Matteo Scandolo27428702019-10-11 16:21:16 -070060var olt OltDevice
Matteo Scandolo84f7d482019-08-08 19:00:47 -070061
Matteo Scandolo27428702019-10-11 16:21:16 -070062func GetOLT() *OltDevice {
63 return &olt
Matteo Scandolo84f7d482019-08-08 19:00:47 -070064}
65
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070066func CreateOLT(seq int, nni int, pon int, onuPerPon int, sTag int, cTagInit int, oltDoneChannel *chan bool, apiDoneChannel *chan bool, group *sync.WaitGroup) OltDevice {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070067 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070068 "ID": seq,
69 "NumNni": nni,
70 "NumPon": pon,
71 "NumOnuPerPon": onuPerPon,
Matteo Scandolo4747d292019-08-05 11:50:18 -070072 }).Debug("CreateOLT")
73
Matteo Scandolo84f7d482019-08-08 19:00:47 -070074 olt = OltDevice{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070075 ID: seq,
Matteo Scandolo8df63df2019-09-12 10:34:32 -070076 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", seq),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070077 OperState: getOperStateFSM(func(e *fsm.Event) {
78 oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
79 }),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070080 NumNni: nni,
81 NumPon: pon,
82 NumOnuPerPon: onuPerPon,
Matteo Scandolo27428702019-10-11 16:21:16 -070083 Pons: []*PonPort{},
84 Nnis: []*NniPort{},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070085 channel: make(chan Message),
86 oltDoneChannel: oltDoneChannel,
87 apiDoneChannel: apiDoneChannel,
88 nniPktInChannel: make(chan *bbsim.PacketMsg, 1024), // packets coming in from the NNI and going to VOLTHA
Matteo Scandolo4747d292019-08-05 11:50:18 -070089 }
90
91 // OLT State machine
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070092 // NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
Matteo Scandolo4747d292019-08-05 11:50:18 -070093 olt.InternalState = fsm.NewFSM(
94 "created",
95 fsm.Events{
96 {Name: "enable", Src: []string{"created"}, Dst: "enabled"},
97 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
98 },
99 fsm.Callbacks{
100 "enter_state": func(e *fsm.Event) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700101 oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700102 },
103 },
104 )
105
106 // create NNI Port
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700107 nniPort, err := CreateNNI(&olt)
108
109 if err != nil {
110 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700111 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700112
Matteo Scandolo27428702019-10-11 16:21:16 -0700113 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700114
115 // create PON ports
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700116 availableCTag := cTagInit
Matteo Scandolo4747d292019-08-05 11:50:18 -0700117 for i := 0; i < pon; i++ {
118 p := PonPort{
119 NumOnu: olt.NumOnuPerPon,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700120 ID: uint32(i),
121 Type: "pon",
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700122 Olt: olt,
Matteo Scandolo27428702019-10-11 16:21:16 -0700123 Onus: []*Onu{},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700124 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700125 p.OperState = getOperStateFSM(func(e *fsm.Event) {
126 oltLogger.WithFields(log.Fields{
127 "ID": p.ID,
128 }).Debugf("Changing PON Port OperState from %s to %s", e.Src, e.Dst)
129 })
Matteo Scandolo4747d292019-08-05 11:50:18 -0700130
131 // create ONU devices
132 for j := 0; j < onuPerPon; j++ {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700133 o := CreateONU(olt, p, uint32(j+1), sTag, availableCTag)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700134 p.Onus = append(p.Onus, o)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700135 availableCTag = availableCTag + 1
Matteo Scandolo4747d292019-08-05 11:50:18 -0700136 }
137
Matteo Scandolo27428702019-10-11 16:21:16 -0700138 olt.Pons = append(olt.Pons, &p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700139 }
140
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700141 newOltServer(olt)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700142
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700143 group.Done()
Matteo Scandolo4747d292019-08-05 11:50:18 -0700144 return olt
145}
146
147func newOltServer(o OltDevice) error {
148 // TODO make configurable
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700149 address := "0.0.0.0:50060"
Matteo Scandolo4747d292019-08-05 11:50:18 -0700150 lis, err := net.Listen("tcp", address)
151 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700152 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700153 }
154 grpcServer := grpc.NewServer()
155 openolt.RegisterOpenoltServer(grpcServer, o)
156
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700157 wg := sync.WaitGroup{}
158 wg.Add(1)
159
Matteo Scandolo4747d292019-08-05 11:50:18 -0700160 go grpcServer.Serve(lis)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700161 oltLogger.Debugf("OLT Listening on: %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700162
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700163 for {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700164 _, ok := <-*o.oltDoneChannel
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700165 if !ok {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700166 // if the olt Channel is closed, stop the gRPC server
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700167 log.Warnf("Stopping OLT gRPC server")
168 grpcServer.Stop()
169 wg.Done()
170 break
171 }
172 }
173
174 wg.Wait()
175
Matteo Scandolo4747d292019-08-05 11:50:18 -0700176 return nil
177}
178
179// Device Methods
180
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700181func (o OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700182
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700183 oltLogger.Debug("Enable OLT called")
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700184
Matteo Scandolo4747d292019-08-05 11:50:18 -0700185 wg := sync.WaitGroup{}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700186 wg.Add(2)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700187
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700188 // create a Channel for all the OLT events
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700189 go o.processOltMessages(stream)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700190 go o.processNniPacketIns(stream)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700191
192 // enable the OLT
193 olt_msg := Message{
194 Type: OltIndication,
195 Data: OltIndicationMessage{
196 OperState: UP,
197 },
198 }
199 o.channel <- olt_msg
200
201 // send NNI Port Indications
202 for _, nni := range o.Nnis {
203 msg := Message{
204 Type: NniIndication,
205 Data: NniIndicationMessage{
206 OperState: UP,
207 NniPortID: nni.ID,
208 },
209 }
210 o.channel <- msg
211 }
212
213 // send PON Port indications
214 for _, pon := range o.Pons {
215 msg := Message{
216 Type: PonIndication,
217 Data: PonIndicationMessage{
218 OperState: UP,
219 PonPortID: pon.ID,
220 },
221 }
222 o.channel <- msg
223
224 for _, onu := range pon.Onus {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700225 go onu.processOnuMessages(stream)
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700226 go onu.processOmciMessages(stream)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700227 // FIXME move the message generation in the state transition
228 // from here only invoke the state transition
Matteo Scandolo4747d292019-08-05 11:50:18 -0700229 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700230 Type: OnuDiscIndication,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700231 Data: OnuDiscIndicationMessage{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700232 Onu: onu,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700233 OperState: UP,
234 },
235 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700236 onu.Channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700237 }
238 }
239
240 wg.Wait()
241 return nil
242}
243
244// Helpers method
245
246func (o OltDevice) getPonById(id uint32) (*PonPort, error) {
247 for _, pon := range o.Pons {
248 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700249 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700250 }
251 }
252 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
253}
254
255func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
256 for _, nni := range o.Nnis {
257 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700258 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700259 }
260 }
261 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
262}
263
Matteo Scandolo4747d292019-08-05 11:50:18 -0700264func (o OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
265 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
266 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700267 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700268 }
269
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700270 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700271 "OperState": msg.OperState,
272 }).Debug("Sent Indication_OltInd")
273}
274
275func (o OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
276 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700277 nni.OperState.Event("enable")
278 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700279 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700280 Type: nni.Type,
281 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700282 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700283 }}
284
285 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700286 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700287 }
288
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700289 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700290 "Type": nni.Type,
291 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700292 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700293 }).Debug("Sent Indication_IntfOperInd for NNI")
294}
295
296func (o OltDevice) sendPonIndication(msg PonIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
297 pon, _ := o.getPonById(msg.PonPortID)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700298 pon.OperState.Event("enable")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700299 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700300 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700301 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700302 }}
303
304 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700305 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700306 }
307
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700308 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700309 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700310 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700311 }).Debug("Sent Indication_IntfInd")
312
313 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700314 Type: pon.Type,
315 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700316 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700317 }}
318
319 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700320 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700321 }
322
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700323 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700324 "Type": pon.Type,
325 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700326 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700327 }).Debug("Sent Indication_IntfOperInd for PON")
328}
329
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700330func (o OltDevice) processOltMessages(stream openolt.Openolt_EnableIndicationServer) {
331 oltLogger.Debug("Started OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700332 for message := range o.channel {
333
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700334 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700335 "oltId": o.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700336 "messageType": message.Type,
337 }).Trace("Received message")
338
339 switch message.Type {
340 case OltIndication:
341 msg, _ := message.Data.(OltIndicationMessage)
342 if msg.OperState == UP {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700343 o.InternalState.Event("enable")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700344 o.OperState.Event("enable")
345 } else if msg.OperState == DOWN {
346 o.InternalState.Event("disable")
347 o.OperState.Event("disable")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700348 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700349 o.sendOltIndication(msg, stream)
350 case NniIndication:
351 msg, _ := message.Data.(NniIndicationMessage)
352 o.sendNniIndication(msg, stream)
353 case PonIndication:
354 msg, _ := message.Data.(PonIndicationMessage)
355 o.sendPonIndication(msg, stream)
356 default:
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700357 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700358 }
359
360 }
361}
362
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700363func (o OltDevice) processNniPacketIns(stream openolt.Openolt_EnableIndicationServer) {
364 oltLogger.WithFields(log.Fields{
365 "nniChannel": o.nniPktInChannel,
366 }).Debug("Started NNI Channel")
367 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
368 for message := range o.nniPktInChannel {
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700369 oltLogger.Tracef("Received packets on NNI Channel")
370
371 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
372
373 if err != nil {
374 log.WithFields(log.Fields{
375 "IntfType": "nni",
376 "IntfId": nniId,
377 "Pkt": message.Pkt.Data(),
Matteo Scandolo27428702019-10-11 16:21:16 -0700378 }).Error("Can't find Dst MacAddress in packet")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700379 return
380 }
381
382 onu, err := o.FindOnuByMacAddress(onuMac)
383 if err != nil {
384 log.WithFields(log.Fields{
385 "IntfType": "nni",
386 "IntfId": nniId,
387 "Pkt": message.Pkt.Data(),
388 "MacAddress": onuMac.String(),
Matteo Scandolo27428702019-10-11 16:21:16 -0700389 }).Error("Can't find ONU with MacAddress")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700390 return
391 }
392
393 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
394 if err != nil {
395 log.Error("Fail to add double tag to packet")
396 }
397
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700398 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
399 IntfType: "nni",
400 IntfId: nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700401 Pkt: doubleTaggedPkt.Data()}}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700402 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
403 oltLogger.WithFields(log.Fields{
404 "IntfType": data.PktInd.IntfType,
405 "IntfId": nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700406 "Pkt": doubleTaggedPkt.Data(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700407 }).Errorf("Fail to send PktInd indication: %v", err)
408 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700409 oltLogger.WithFields(log.Fields{
410 "IntfType": data.PktInd.IntfType,
411 "IntfId": nniId,
412 "Pkt": doubleTaggedPkt.Data(),
413 }).Tracef("Sent PktInd indication")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700414 }
415}
416
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700417// returns an ONU with a given Serial Number
418func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
419 // TODO this function can be a perfoormance bottlenec when we have many ONUs,
420 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700421 for _, pon := range o.Pons {
422 for _, onu := range pon.Onus {
423 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700424 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700425 }
426 }
427 }
428
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700429 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-serial-number-%s", serialNumber))
430}
431
432// returns an ONU with a given Mac Address
433func (o OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*Onu, error) {
434 // TODO this function can be a perfoormance bottlenec when we have many ONUs,
435 // memoizing it will remove the bottleneck
436 for _, pon := range o.Pons {
437 for _, onu := range pon.Onus {
438 if onu.HwAddress.String() == mac.String() {
Matteo Scandolo27428702019-10-11 16:21:16 -0700439 return onu, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700440 }
441 }
442 }
443
444 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-mac-address-%s", mac))
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700445}
446
Matteo Scandolo4747d292019-08-05 11:50:18 -0700447// GRPC Endpoints
448
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700449func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700450 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700451 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700452 }).Info("Received ActivateOnu call from VOLTHA")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700453
454 pon, _ := o.getPonById(onu.IntfId)
455 _onu, _ := pon.getOnuBySn(onu.SerialNumber)
456
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700457 if err := _onu.OperState.Event("enable"); err != nil {
458 oltLogger.WithFields(log.Fields{
459 "IntfId": _onu.PonPortID,
460 "OnuSn": _onu.Sn(),
461 "OnuId": _onu.ID,
462 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700463 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700464 if err := _onu.InternalState.Event("enable"); err != nil {
465 oltLogger.WithFields(log.Fields{
466 "IntfId": _onu.PonPortID,
467 "OnuSn": _onu.Sn(),
468 "OnuId": _onu.ID,
469 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
470 }
471
472 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
473
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700474 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700475}
476
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700477func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700478 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700479 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700480}
481
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700482func (o OltDevice) DeleteOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700483 oltLogger.Error("DeleteOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700484 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700485}
486
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700487func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700488 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
489 olt_msg := Message{
490 Type: OltIndication,
491 Data: OltIndicationMessage{
492 OperState: DOWN,
493 },
494 }
495 o.channel <- olt_msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700496 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700497}
498
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700499func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700500 oltLogger.Error("DisablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700501 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700502}
503
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700504func (o OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700505 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700506 o.Enable(stream)
507 return nil
508}
509
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700510func (o OltDevice) EnablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700511 oltLogger.Error("EnablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700512 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700513}
514
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700515func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700516 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700517 "IntfId": flow.AccessIntfId,
518 "OnuId": flow.OnuId,
519 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700520 "InnerVlan": flow.Classifier.IVid,
521 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700522 "FlowType": flow.FlowType,
523 "FlowId": flow.FlowId,
524 "UniID": flow.UniId,
525 "PortNo": flow.PortNo,
526 }).Tracef("OLT receives Flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700527 // TODO optionally store flows somewhere
528
529 if flow.AccessIntfId == -1 {
530 oltLogger.WithFields(log.Fields{
531 "FlowId": flow.FlowId,
532 }).Debugf("This is an OLT flow")
533 } else {
Matteo Scandolo27428702019-10-11 16:21:16 -0700534 pon, err := o.getPonById(uint32(flow.AccessIntfId))
535 if err != nil {
536 oltLogger.WithFields(log.Fields{
537 "OnuId": flow.OnuId,
538 "IntfId": flow.AccessIntfId,
539 "err": err,
540 }).Error("Can't find PonPort")
541 }
542 onu, err := pon.getOnuById(uint32(flow.OnuId))
543 if err != nil {
544 oltLogger.WithFields(log.Fields{
545 "OnuId": flow.OnuId,
546 "IntfId": flow.AccessIntfId,
547 "err": err,
548 }).Error("Can't find Onu")
549 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700550
551 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700552 Type: FlowUpdate,
553 Data: OnuFlowUpdateMessage{
554 PonPortID: pon.ID,
555 OnuID: onu.ID,
556 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700557 },
558 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700559 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700560 }
561
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700562 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700563}
564
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700565func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
566 oltLogger.Tracef("received FlowRemove")
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700567 // TODO store flows somewhere
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700568 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700569}
570
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700571func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700572 oltLogger.Error("HeartbeatCheck not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700573 return new(openolt.Heartbeat), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700574}
575
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700576func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700577
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700578 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700579 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700580 "PonPorts": o.NumPon,
581 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700582 devinfo := new(openolt.DeviceInfo)
583 devinfo.Vendor = "BBSim"
584 devinfo.Model = "asfvolt16"
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700585 devinfo.HardwareVersion = "emulated"
Matteo Scandolo4747d292019-08-05 11:50:18 -0700586 devinfo.FirmwareVersion = ""
587 devinfo.Technology = "xgspon"
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700588 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700589 devinfo.OnuIdStart = 1
590 devinfo.OnuIdEnd = 255
591 devinfo.AllocIdStart = 1024
592 devinfo.AllocIdEnd = 16383
593 devinfo.GemportIdStart = 1024
594 devinfo.GemportIdEnd = 65535
595 devinfo.FlowIdStart = 1
596 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -0700597 devinfo.DeviceSerialNumber = o.SerialNumber
Matteo Scandolo4747d292019-08-05 11:50:18 -0700598
599 return devinfo, nil
600}
601
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700602func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700603 pon, _ := o.getPonById(omci_msg.IntfId)
604 onu, _ := pon.getOnuById(omci_msg.OnuId)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700605 oltLogger.WithFields(log.Fields{
606 "IntfId": onu.PonPortID,
607 "OnuId": onu.ID,
608 "OnuSn": onu.Sn(),
609 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700610 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700611 Type: OMCI,
612 Data: OmciMessage{
613 OnuSN: onu.SerialNumber,
614 OnuID: onu.ID,
615 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700616 },
617 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700618 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700619 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700620}
621
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700622func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo27428702019-10-11 16:21:16 -0700623 pon, err := o.getPonById(onuPkt.IntfId)
624 if err != nil {
625 oltLogger.WithFields(log.Fields{
626 "OnuId": onuPkt.OnuId,
627 "IntfId": onuPkt.IntfId,
628 "err": err,
629 }).Error("Can't find PonPort")
630 }
631 onu, err := pon.getOnuById(onuPkt.OnuId)
632 if err != nil {
633 oltLogger.WithFields(log.Fields{
634 "OnuId": onuPkt.OnuId,
635 "IntfId": onuPkt.IntfId,
636 "err": err,
637 }).Error("Can't find Onu")
638 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700639
Matteo Scandolo075b1892019-10-07 12:11:07 -0700640 oltLogger.WithFields(log.Fields{
641 "IntfId": onu.PonPortID,
642 "OnuId": onu.ID,
643 "OnuSn": onu.Sn(),
644 }).Tracef("Received OnuPacketOut")
645
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700646 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
647
Matteo Scandolo075b1892019-10-07 12:11:07 -0700648 msg := Message{
649 Type: OnuPacketOut,
650 Data: OnuPacketOutMessage{
651 IntfId: onuPkt.IntfId,
652 OnuId: onuPkt.OnuId,
653 Packet: rawpkt,
654 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700655 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700656 onu.Channel <- msg
657
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700658 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700659}
660
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700661func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700662 oltLogger.Info("Shutting Down")
663 close(*o.oltDoneChannel)
664 close(*o.apiDoneChannel)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700665 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700666}
667
668func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700669 oltLogger.Error("ReenableOlt not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700670 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700671}
672
673func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700674 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
675
676 sendNniPacket(pkt)
677 // NOTE should we return an error if sendNniPakcet fails?
678 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700679}
680
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700681func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700682 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700683 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700684}
685
Matteo Scandolo4747d292019-08-05 11:50:18 -0700686func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700687 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700688 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700689}
690
691func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700692 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700693 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -0700694}
695
696func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700697 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700698 return new(openolt.Empty), nil
699}
700
701func (s OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700702 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700703 return new(openolt.Empty), nil
704}
705
706func (s OltDevice) CreateTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700707 oltLogger.Info("received CreateTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700708 return new(openolt.Empty), nil
709}
710
711func (s OltDevice) RemoveTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700712 oltLogger.Info("received RemoveTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700713 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700714}