blob: 27f4e788216eaca164cfccaabdc2530784da36f6 [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 Scandolo40e067f2019-10-16 16:59:41 -070066func CreateOLT(oltId int, nni int, pon int, onuPerPon int, sTag int, cTagInit int, oltDoneChannel *chan bool, apiDoneChannel *chan bool, isMock bool) *OltDevice {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070067 oltLogger.WithFields(log.Fields{
Matteo Scandolo40e067f2019-10-16 16:59:41 -070068 "ID": oltId,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070069 "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 Scandolo40e067f2019-10-16 16:59:41 -070075 ID: oltId,
76 SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", oltId),
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
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700106 if isMock != true {
107 // create NNI Port
108 nniPort, err := CreateNNI(&olt)
109 if err != nil {
110 oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
111 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700112
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700113 olt.Nnis = append(olt.Nnis, &nniPort)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700114 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700115
Matteo Scandolo4747d292019-08-05 11:50:18 -0700116 // create PON ports
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700117 availableCTag := cTagInit
Matteo Scandolo4747d292019-08-05 11:50:18 -0700118 for i := 0; i < pon; i++ {
119 p := PonPort{
120 NumOnu: olt.NumOnuPerPon,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700121 ID: uint32(i),
122 Type: "pon",
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700123 Olt: olt,
Matteo Scandolo27428702019-10-11 16:21:16 -0700124 Onus: []*Onu{},
Matteo Scandolo4747d292019-08-05 11:50:18 -0700125 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700126 p.OperState = getOperStateFSM(func(e *fsm.Event) {
127 oltLogger.WithFields(log.Fields{
128 "ID": p.ID,
129 }).Debugf("Changing PON Port OperState from %s to %s", e.Src, e.Dst)
130 })
Matteo Scandolo4747d292019-08-05 11:50:18 -0700131
132 // create ONU devices
133 for j := 0; j < onuPerPon; j++ {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700134 o := CreateONU(olt, p, uint32(j+1), sTag, availableCTag)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700135 p.Onus = append(p.Onus, o)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700136 availableCTag = availableCTag + 1
Matteo Scandolo4747d292019-08-05 11:50:18 -0700137 }
138
Matteo Scandolo27428702019-10-11 16:21:16 -0700139 olt.Pons = append(olt.Pons, &p)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700140 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700141 return &olt
142}
Matteo Scandolo4747d292019-08-05 11:50:18 -0700143
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700144// this function start the OLT gRPC server and blocks until it's done
145func StartOlt(olt *OltDevice, group *sync.WaitGroup) {
146 newOltServer(*olt)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700147 group.Done()
Matteo Scandolo4747d292019-08-05 11:50:18 -0700148}
149
150func newOltServer(o OltDevice) error {
151 // TODO make configurable
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700152 address := "0.0.0.0:50060"
Matteo Scandolo4747d292019-08-05 11:50:18 -0700153 lis, err := net.Listen("tcp", address)
154 if err != nil {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700155 oltLogger.Fatalf("OLT failed to listen: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700156 }
157 grpcServer := grpc.NewServer()
158 openolt.RegisterOpenoltServer(grpcServer, o)
159
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700160 wg := sync.WaitGroup{}
161 wg.Add(1)
162
Matteo Scandolo4747d292019-08-05 11:50:18 -0700163 go grpcServer.Serve(lis)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700164 oltLogger.Debugf("OLT Listening on: %v", address)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700165
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700166 for {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700167 _, ok := <-*o.oltDoneChannel
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700168 if !ok {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700169 // if the olt Channel is closed, stop the gRPC server
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700170 log.Warnf("Stopping OLT gRPC server")
171 grpcServer.Stop()
172 wg.Done()
173 break
174 }
175 }
176
177 wg.Wait()
178
Matteo Scandolo4747d292019-08-05 11:50:18 -0700179 return nil
180}
181
182// Device Methods
183
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700184func (o OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700185
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700186 oltLogger.Debug("Enable OLT called")
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700187
Matteo Scandolo4747d292019-08-05 11:50:18 -0700188 wg := sync.WaitGroup{}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700189 wg.Add(2)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700190
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700191 // create a Channel for all the OLT events
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700192 go o.processOltMessages(stream)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700193 go o.processNniPacketIns(stream)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700194
195 // enable the OLT
196 olt_msg := Message{
197 Type: OltIndication,
198 Data: OltIndicationMessage{
199 OperState: UP,
200 },
201 }
202 o.channel <- olt_msg
203
204 // send NNI Port Indications
205 for _, nni := range o.Nnis {
206 msg := Message{
207 Type: NniIndication,
208 Data: NniIndicationMessage{
209 OperState: UP,
210 NniPortID: nni.ID,
211 },
212 }
213 o.channel <- msg
214 }
215
216 // send PON Port indications
217 for _, pon := range o.Pons {
218 msg := Message{
219 Type: PonIndication,
220 Data: PonIndicationMessage{
221 OperState: UP,
222 PonPortID: pon.ID,
223 },
224 }
225 o.channel <- msg
226
227 for _, onu := range pon.Onus {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700228 go onu.ProcessOnuMessages(stream, nil)
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700229 go onu.processOmciMessages(stream)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700230 // FIXME move the message generation in the state transition
231 // from here only invoke the state transition
Matteo Scandolo4747d292019-08-05 11:50:18 -0700232 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700233 Type: OnuDiscIndication,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700234 Data: OnuDiscIndicationMessage{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700235 Onu: onu,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700236 OperState: UP,
237 },
238 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700239 onu.Channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700240 }
241 }
242
243 wg.Wait()
244 return nil
245}
246
247// Helpers method
248
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700249func (o OltDevice) GetPonById(id uint32) (*PonPort, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700250 for _, pon := range o.Pons {
251 if pon.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700252 return pon, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700253 }
254 }
255 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
256}
257
258func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
259 for _, nni := range o.Nnis {
260 if nni.ID == id {
Matteo Scandolo27428702019-10-11 16:21:16 -0700261 return nni, nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700262 }
263 }
264 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
265}
266
Matteo Scandolo4747d292019-08-05 11:50:18 -0700267func (o OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
268 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
269 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700270 oltLogger.Errorf("Failed to send Indication_OltInd: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700271 }
272
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700273 oltLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700274 "OperState": msg.OperState,
275 }).Debug("Sent Indication_OltInd")
276}
277
278func (o OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
279 nni, _ := o.getNniById(msg.NniPortID)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700280 nni.OperState.Event("enable")
281 // NOTE Operstate may need to be an integer
Matteo Scandolo4747d292019-08-05 11:50:18 -0700282 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700283 Type: nni.Type,
284 IntfId: nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700285 OperState: nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700286 }}
287
288 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700289 oltLogger.Errorf("Failed to send Indication_IntfOperInd for NNI: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700290 }
291
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700292 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700293 "Type": nni.Type,
294 "IntfId": nni.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700295 "OperState": nni.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700296 }).Debug("Sent Indication_IntfOperInd for NNI")
297}
298
299func (o OltDevice) sendPonIndication(msg PonIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700300 pon, _ := o.GetPonById(msg.PonPortID)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700301 pon.OperState.Event("enable")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700302 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700303 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700304 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700305 }}
306
307 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700308 oltLogger.Errorf("Failed to send Indication_IntfInd: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700309 }
310
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700311 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700312 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700313 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700314 }).Debug("Sent Indication_IntfInd")
315
316 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700317 Type: pon.Type,
318 IntfId: pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700319 OperState: pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700320 }}
321
322 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700323 oltLogger.Errorf("Failed to send Indication_IntfOperInd for PON: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700324 }
325
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700326 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700327 "Type": pon.Type,
328 "IntfId": pon.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700329 "OperState": pon.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700330 }).Debug("Sent Indication_IntfOperInd for PON")
331}
332
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700333func (o OltDevice) processOltMessages(stream openolt.Openolt_EnableIndicationServer) {
334 oltLogger.Debug("Started OLT Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700335 for message := range o.channel {
336
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700337 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700338 "oltId": o.ID,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700339 "messageType": message.Type,
340 }).Trace("Received message")
341
342 switch message.Type {
343 case OltIndication:
344 msg, _ := message.Data.(OltIndicationMessage)
345 if msg.OperState == UP {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700346 o.InternalState.Event("enable")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700347 o.OperState.Event("enable")
348 } else if msg.OperState == DOWN {
349 o.InternalState.Event("disable")
350 o.OperState.Event("disable")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700351 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700352 o.sendOltIndication(msg, stream)
353 case NniIndication:
354 msg, _ := message.Data.(NniIndicationMessage)
355 o.sendNniIndication(msg, stream)
356 case PonIndication:
357 msg, _ := message.Data.(PonIndicationMessage)
358 o.sendPonIndication(msg, stream)
359 default:
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700360 oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700361 }
362
363 }
364}
365
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700366func (o OltDevice) processNniPacketIns(stream openolt.Openolt_EnableIndicationServer) {
367 oltLogger.WithFields(log.Fields{
368 "nniChannel": o.nniPktInChannel,
369 }).Debug("Started NNI Channel")
370 nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
371 for message := range o.nniPktInChannel {
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700372 oltLogger.Tracef("Received packets on NNI Channel")
373
374 onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
375
376 if err != nil {
377 log.WithFields(log.Fields{
378 "IntfType": "nni",
379 "IntfId": nniId,
380 "Pkt": message.Pkt.Data(),
Matteo Scandolo27428702019-10-11 16:21:16 -0700381 }).Error("Can't find Dst MacAddress in packet")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700382 return
383 }
384
385 onu, err := o.FindOnuByMacAddress(onuMac)
386 if err != nil {
387 log.WithFields(log.Fields{
388 "IntfType": "nni",
389 "IntfId": nniId,
390 "Pkt": message.Pkt.Data(),
391 "MacAddress": onuMac.String(),
Matteo Scandolo27428702019-10-11 16:21:16 -0700392 }).Error("Can't find ONU with MacAddress")
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700393 return
394 }
395
396 doubleTaggedPkt, err := packetHandlers.PushDoubleTag(onu.STag, onu.CTag, message.Pkt)
397 if err != nil {
398 log.Error("Fail to add double tag to packet")
399 }
400
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700401 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
402 IntfType: "nni",
403 IntfId: nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700404 Pkt: doubleTaggedPkt.Data()}}
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700405 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
406 oltLogger.WithFields(log.Fields{
407 "IntfType": data.PktInd.IntfType,
408 "IntfId": nniId,
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700409 "Pkt": doubleTaggedPkt.Data(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700410 }).Errorf("Fail to send PktInd indication: %v", err)
411 }
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700412 oltLogger.WithFields(log.Fields{
413 "IntfType": data.PktInd.IntfType,
414 "IntfId": nniId,
415 "Pkt": doubleTaggedPkt.Data(),
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700416 "OnuSn": onu.Sn(),
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700417 }).Tracef("Sent PktInd indication")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700418 }
419}
420
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700421// returns an ONU with a given Serial Number
422func (o OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
423 // TODO this function can be a perfoormance bottlenec when we have many ONUs,
424 // memoizing it will remove the bottleneck
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700425 for _, pon := range o.Pons {
426 for _, onu := range pon.Onus {
427 if onu.Sn() == serialNumber {
Matteo Scandolo27428702019-10-11 16:21:16 -0700428 return onu, nil
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700429 }
430 }
431 }
432
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700433 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-serial-number-%s", serialNumber))
434}
435
436// returns an ONU with a given Mac Address
437func (o OltDevice) FindOnuByMacAddress(mac net.HardwareAddr) (*Onu, error) {
438 // TODO this function can be a perfoormance bottlenec when we have many ONUs,
439 // memoizing it will remove the bottleneck
440 for _, pon := range o.Pons {
441 for _, onu := range pon.Onus {
442 if onu.HwAddress.String() == mac.String() {
Matteo Scandolo27428702019-10-11 16:21:16 -0700443 return onu, nil
Matteo Scandolof6f3a7f2019-10-11 11:19:29 -0700444 }
445 }
446 }
447
448 return &Onu{}, errors.New(fmt.Sprintf("cannot-find-onu-by-mac-address-%s", mac))
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700449}
450
Matteo Scandolo4747d292019-08-05 11:50:18 -0700451// GRPC Endpoints
452
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700453func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700454 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700455 "OnuSn": onuSnToString(onu.SerialNumber),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700456 }).Info("Received ActivateOnu call from VOLTHA")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700457
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700458 pon, _ := o.GetPonById(onu.IntfId)
459 _onu, _ := pon.GetOnuBySn(onu.SerialNumber)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700460
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700461 if err := _onu.OperState.Event("enable"); err != nil {
462 oltLogger.WithFields(log.Fields{
463 "IntfId": _onu.PonPortID,
464 "OnuSn": _onu.Sn(),
465 "OnuId": _onu.ID,
466 }).Infof("Failed to transition ONU.OperState to enabled state: %s", err.Error())
Matteo Scandolo4747d292019-08-05 11:50:18 -0700467 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700468 if err := _onu.InternalState.Event("enable"); err != nil {
469 oltLogger.WithFields(log.Fields{
470 "IntfId": _onu.PonPortID,
471 "OnuSn": _onu.Sn(),
472 "OnuId": _onu.ID,
473 }).Infof("Failed to transition ONU to enabled state: %s", err.Error())
474 }
475
476 // NOTE we need to immediately activate the ONU or the OMCI state machine won't start
477
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700478 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700479}
480
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700481func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700482 oltLogger.Error("DeactivateOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700483 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700484}
485
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700486func (o OltDevice) DeleteOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700487 oltLogger.Error("DeleteOnu not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700488 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700489}
490
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700491func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700492 // NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
493 olt_msg := Message{
494 Type: OltIndication,
495 Data: OltIndicationMessage{
496 OperState: DOWN,
497 },
498 }
499 o.channel <- olt_msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700500 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700501}
502
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700503func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700504 oltLogger.Error("DisablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700505 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700506}
507
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700508func (o OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700509 oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700510 o.Enable(stream)
511 return nil
512}
513
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700514func (o OltDevice) EnablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700515 oltLogger.Error("EnablePonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700516 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700517}
518
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700519func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700520 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700521 "IntfId": flow.AccessIntfId,
522 "OnuId": flow.OnuId,
523 "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700524 "InnerVlan": flow.Classifier.IVid,
525 "OuterVlan": flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700526 "FlowType": flow.FlowType,
527 "FlowId": flow.FlowId,
528 "UniID": flow.UniId,
529 "PortNo": flow.PortNo,
530 }).Tracef("OLT receives Flow")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700531 // TODO optionally store flows somewhere
532
533 if flow.AccessIntfId == -1 {
534 oltLogger.WithFields(log.Fields{
535 "FlowId": flow.FlowId,
536 }).Debugf("This is an OLT flow")
537 } else {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700538 pon, err := o.GetPonById(uint32(flow.AccessIntfId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700539 if err != nil {
540 oltLogger.WithFields(log.Fields{
541 "OnuId": flow.OnuId,
542 "IntfId": flow.AccessIntfId,
543 "err": err,
544 }).Error("Can't find PonPort")
545 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700546 onu, err := pon.GetOnuById(uint32(flow.OnuId))
Matteo Scandolo27428702019-10-11 16:21:16 -0700547 if err != nil {
548 oltLogger.WithFields(log.Fields{
549 "OnuId": flow.OnuId,
550 "IntfId": flow.AccessIntfId,
551 "err": err,
552 }).Error("Can't find Onu")
553 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700554
555 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700556 Type: FlowUpdate,
557 Data: OnuFlowUpdateMessage{
558 PonPortID: pon.ID,
559 OnuID: onu.ID,
560 Flow: flow,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700561 },
562 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700563 onu.Channel <- msg
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700564 }
565
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700566 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700567}
568
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700569func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
570 oltLogger.Tracef("received FlowRemove")
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700571 // TODO store flows somewhere
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700572 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700573}
574
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700575func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700576 oltLogger.Error("HeartbeatCheck not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700577 return new(openolt.Heartbeat), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700578}
579
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700580func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700581
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700582 oltLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700583 "oltId": o.ID,
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700584 "PonPorts": o.NumPon,
585 }).Info("OLT receives GetDeviceInfo call from VOLTHA")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700586 devinfo := new(openolt.DeviceInfo)
587 devinfo.Vendor = "BBSim"
588 devinfo.Model = "asfvolt16"
Matteo Scandolo84f7d482019-08-08 19:00:47 -0700589 devinfo.HardwareVersion = "emulated"
Matteo Scandolo4747d292019-08-05 11:50:18 -0700590 devinfo.FirmwareVersion = ""
591 devinfo.Technology = "xgspon"
Matteo Scandoloda9cbe22019-08-19 16:05:10 -0700592 devinfo.PonPorts = uint32(o.NumPon)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700593 devinfo.OnuIdStart = 1
594 devinfo.OnuIdEnd = 255
595 devinfo.AllocIdStart = 1024
596 devinfo.AllocIdEnd = 16383
597 devinfo.GemportIdStart = 1024
598 devinfo.GemportIdEnd = 65535
599 devinfo.FlowIdStart = 1
600 devinfo.FlowIdEnd = 16383
Matteo Scandolo8df63df2019-09-12 10:34:32 -0700601 devinfo.DeviceSerialNumber = o.SerialNumber
Matteo Scandolo4747d292019-08-05 11:50:18 -0700602
603 return devinfo, nil
604}
605
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700606func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700607 pon, _ := o.GetPonById(omci_msg.IntfId)
608 onu, _ := pon.GetOnuById(omci_msg.OnuId)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700609 oltLogger.WithFields(log.Fields{
610 "IntfId": onu.PonPortID,
611 "OnuId": onu.ID,
612 "OnuSn": onu.Sn(),
613 }).Tracef("Received OmciMsgOut")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700614 msg := Message{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700615 Type: OMCI,
616 Data: OmciMessage{
617 OnuSN: onu.SerialNumber,
618 OnuID: onu.ID,
619 omciMsg: omci_msg,
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700620 },
621 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700622 onu.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700623 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700624}
625
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700626func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700627 pon, err := o.GetPonById(onuPkt.IntfId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700628 if err != nil {
629 oltLogger.WithFields(log.Fields{
630 "OnuId": onuPkt.OnuId,
631 "IntfId": onuPkt.IntfId,
632 "err": err,
633 }).Error("Can't find PonPort")
634 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700635 onu, err := pon.GetOnuById(onuPkt.OnuId)
Matteo Scandolo27428702019-10-11 16:21:16 -0700636 if err != nil {
637 oltLogger.WithFields(log.Fields{
638 "OnuId": onuPkt.OnuId,
639 "IntfId": onuPkt.IntfId,
640 "err": err,
641 }).Error("Can't find Onu")
642 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700643
Matteo Scandolo075b1892019-10-07 12:11:07 -0700644 oltLogger.WithFields(log.Fields{
645 "IntfId": onu.PonPortID,
646 "OnuId": onu.ID,
647 "OnuSn": onu.Sn(),
648 }).Tracef("Received OnuPacketOut")
649
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700650 rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700651 pktType, err := packetHandlers.IsEapolOrDhcp(rawpkt)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700652
Matteo Scandolo075b1892019-10-07 12:11:07 -0700653 msg := Message{
654 Type: OnuPacketOut,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700655 Data: OnuPacketMessage{
Matteo Scandolo075b1892019-10-07 12:11:07 -0700656 IntfId: onuPkt.IntfId,
657 OnuId: onuPkt.OnuId,
658 Packet: rawpkt,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700659 Type: pktType,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700660 },
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700661 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700662 onu.Channel <- msg
663
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700664 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700665}
666
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700667func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700668 oltLogger.Info("Shutting Down")
669 close(*o.oltDoneChannel)
670 close(*o.apiDoneChannel)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700671 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700672}
673
674func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700675 oltLogger.Error("ReenableOlt not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700676 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700677}
678
679func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700680 pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
681
682 sendNniPacket(pkt)
683 // NOTE should we return an error if sendNniPakcet fails?
684 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700685}
686
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700687func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700688 oltLogger.Error("CollectStatistics not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700689 return new(openolt.Empty), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700690}
691
Matteo Scandolo4747d292019-08-05 11:50:18 -0700692func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700693 oltLogger.Error("GetOnuInfo not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700694 return new(openolt.OnuIndication), nil
Matteo Scandolo4747d292019-08-05 11:50:18 -0700695}
696
697func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700698 oltLogger.Error("GetPonIf not implemented")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700699 return new(openolt.IntfIndication), nil
Matteo Scandolod54283a2019-08-13 16:22:31 -0700700}
701
702func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700703 oltLogger.Info("received CreateTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700704 return new(openolt.Empty), nil
705}
706
707func (s OltDevice) RemoveTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700708 oltLogger.Info("received RemoveTrafficQueues")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700709 return new(openolt.Empty), nil
710}
711
712func (s OltDevice) CreateTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700713 oltLogger.Info("received CreateTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700714 return new(openolt.Empty), nil
715}
716
717func (s OltDevice) RemoveTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700718 oltLogger.Info("received RemoveTrafficSchedulers")
Matteo Scandolod54283a2019-08-13 16:22:31 -0700719 return new(openolt.Empty), nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700720}