blob: 8435af1d16cd4b987df79be27988dcd99486de50 [file] [log] [blame]
Matteo Scandolo4747d292019-08-05 11:50:18 -07001package devices
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "gerrit.opencord.org/bbsim/api"
8 "github.com/looplab/fsm"
9 log "github.com/sirupsen/logrus"
10 "google.golang.org/grpc"
11 "net"
12 "sync"
13)
14
15func init() {
16 //log.SetReportCaller(true)
17 log.SetLevel(log.DebugLevel)
18}
19
20func CreateOLT(seq int, nni int, pon int, onuPerPon int) OltDevice {
21 log.WithFields(log.Fields{
22 "ID": seq,
23 "NumNni":nni,
24 "NumPon":pon,
25 "NumOnuPerPon":onuPerPon,
26 }).Debug("CreateOLT")
27
28 olt := OltDevice{
29 ID: seq,
30 NumNni:nni,
31 NumPon:pon,
32 NumOnuPerPon:onuPerPon,
33 Pons: []PonPort{},
34 Nnis: []NniPort{},
35 channel: make(chan interface{}, 32),
36 }
37
38 // OLT State machine
39 olt.InternalState = fsm.NewFSM(
40 "created",
41 fsm.Events{
42 {Name: "enable", Src: []string{"created"}, Dst: "enabled"},
43 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
44 },
45 fsm.Callbacks{
46 "enter_state": func(e *fsm.Event) {
47 olt.stateChange(e)
48 },
49 },
50 )
51
52 // create NNI Port
53 nniPort := NniPort{
54 ID: uint32(0),
55 OperState: DOWN,
56 Type: "nni",
57 }
58 olt.Nnis = append(olt.Nnis, nniPort)
59
60 // create PON ports
61 for i := 0; i < pon; i++ {
62 p := PonPort{
63 NumOnu: olt.NumOnuPerPon,
64 ID: uint32(i),
65 OperState: DOWN,
66 Type: "pon",
67 }
68
69 // create ONU devices
70 for j := 0; j < onuPerPon; j++ {
71 o := CreateONU(olt, p, uint32(j + 1))
72 p.Onus = append(p.Onus, o)
73 }
74
75 olt.Pons = append(olt.Pons, p)
76 }
77
78 wg := sync.WaitGroup{}
79
80 wg.Add(1)
81 go newOltServer(olt)
82 wg.Wait()
83 return olt
84}
85
86func newOltServer(o OltDevice) error {
87 // TODO make configurable
88 address := "0.0.0.0:50060"
89 log.Debugf("OLT Listening on: %v", address)
90 lis, err := net.Listen("tcp", address)
91 if err != nil {
92 log.Fatalf("failed to listen: %v", err)
93 }
94 grpcServer := grpc.NewServer()
95 openolt.RegisterOpenoltServer(grpcServer, o)
96
97 go grpcServer.Serve(lis)
98
99 return nil
100}
101
102// Device Methods
103
104func (o OltDevice) Enable (stream openolt.Openolt_EnableIndicationServer) error {
105
106 wg := sync.WaitGroup{}
107 wg.Add(1)
108
109 // create a channel for all the OLT events
110 go o.oltChannels(stream)
111
112 // enable the OLT
113 olt_msg := Message{
114 Type: OltIndication,
115 Data: OltIndicationMessage{
116 OperState: UP,
117 },
118 }
119 o.channel <- olt_msg
120
121 // send NNI Port Indications
122 for _, nni := range o.Nnis {
123 msg := Message{
124 Type: NniIndication,
125 Data: NniIndicationMessage{
126 OperState: UP,
127 NniPortID: nni.ID,
128 },
129 }
130 o.channel <- msg
131 }
132
133 // send PON Port indications
134 for _, pon := range o.Pons {
135 msg := Message{
136 Type: PonIndication,
137 Data: PonIndicationMessage{
138 OperState: UP,
139 PonPortID: pon.ID,
140 },
141 }
142 o.channel <- msg
143
144 for _, onu := range pon.Onus {
145 msg := Message{
146 Type: OnuDiscIndication,
147 Data: OnuDiscIndicationMessage{
148 Onu: onu,
149 OperState: UP,
150 },
151 }
152 o.channel <- msg
153 }
154 }
155
156 wg.Wait()
157 return nil
158}
159
160// Helpers method
161
162func (o OltDevice) getPonById(id uint32) (*PonPort, error) {
163 for _, pon := range o.Pons {
164 if pon.ID == id {
165 return &pon, nil
166 }
167 }
168 return nil, errors.New(fmt.Sprintf("Cannot find PonPort with id %d in OLT %d", id, o.ID))
169}
170
171func (o OltDevice) getNniById(id uint32) (*NniPort, error) {
172 for _, nni := range o.Nnis {
173 if nni.ID == id {
174 return &nni, nil
175 }
176 }
177 return nil, errors.New(fmt.Sprintf("Cannot find NniPort with id %d in OLT %d", id, o.ID))
178}
179
180func (o OltDevice) stateChange(e *fsm.Event) {
181 log.WithFields(log.Fields{
182 "oltId": o.ID,
183 "dstState": e.Dst,
184 "srcState": e.Src,
185 }).Debugf("OLT state has changed")
186}
187
188func (o OltDevice) sendOltIndication(msg OltIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
189 data := &openolt.Indication_OltInd{OltInd: &openolt.OltIndication{OperState: msg.OperState.String()}}
190 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
191 log.Error("Failed to send Indication_OltInd: %v", err)
192 }
193
194 log.WithFields(log.Fields{
195 "OperState": msg.OperState,
196 }).Debug("Sent Indication_OltInd")
197}
198
199func (o OltDevice) sendNniIndication(msg NniIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
200 nni, _ := o.getNniById(msg.NniPortID)
201 nni.OperState = UP
202 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
203 Type: nni.Type,
204 IntfId: nni.ID,
205 OperState: nni.OperState.String(),
206 }}
207
208 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
209 log.Error("Failed to send Indication_IntfOperInd for NNI: %v", err)
210 }
211
212 log.WithFields(log.Fields{
213 "Type": nni.Type,
214 "IntfId": nni.ID,
215 "OperState": nni.OperState.String(),
216 }).Debug("Sent Indication_IntfOperInd for NNI")
217}
218
219func (o OltDevice) sendPonIndication(msg PonIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
220 pon, _ := o.getPonById(msg.PonPortID)
221 pon.OperState = UP
222 discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
223 IntfId: pon.ID,
224 OperState: pon.OperState.String(),
225 }}
226
227 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
228 log.Error("Failed to send Indication_IntfInd: %v", err)
229 }
230
231 log.WithFields(log.Fields{
232 "IntfId": pon.ID,
233 "OperState": pon.OperState.String(),
234 }).Debug("Sent Indication_IntfInd")
235
236 operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
237 Type: pon.Type,
238 IntfId: pon.ID,
239 OperState: pon.OperState.String(),
240 }}
241
242 if err := stream.Send(&openolt.Indication{Data: operData}); err != nil {
243 log.Error("Failed to send Indication_IntfOperInd for PON: %v", err)
244 }
245
246 log.WithFields(log.Fields{
247 "Type": pon.Type,
248 "IntfId": pon.ID,
249 "OperState": pon.OperState.String(),
250 }).Debug("Sent Indication_IntfOperInd for PON")
251}
252
253func (o OltDevice) oltChannels(stream openolt.Openolt_EnableIndicationServer) {
254
255 for message := range o.channel {
256
257 _msg, _ok := message.(Message)
258 if _ok {
259 log.WithFields(log.Fields{
260 "oltId": o.ID,
261 "messageType": _msg.Type,
262 }).Debug("Received message")
263
264 switch _msg.Data.(type) {
265 case OltIndicationMessage:
266 msg, _ := _msg.Data.(OltIndicationMessage)
267 o.InternalState.Event("enable")
268 o.sendOltIndication(msg, stream)
269 case NniIndicationMessage:
270 msg, _ := _msg.Data.(NniIndicationMessage)
271 o.sendNniIndication(msg, stream)
272 case PonIndicationMessage:
273 msg, _ := _msg.Data.(PonIndicationMessage)
274 o.sendPonIndication(msg, stream)
275 case OnuDiscIndicationMessage:
276 msg, _ := _msg.Data.(OnuDiscIndicationMessage)
277 msg.Onu.InternalState.Event("discover")
278 msg.Onu.sendOnuDiscIndication(msg, stream)
279 case OnuIndicationMessage:
280 msg, _ := _msg.Data.(OnuIndicationMessage)
281 pon, _ := o.getPonById(msg.PonPortID)
282 onu, _ := pon.getOnuBySn(msg.OnuSN)
283 onu.InternalState.Event("enable")
284 onu.sendOnuIndication(msg, stream)
285 default:
286 log.Warnf("Received unkown message data %v for type %v", _msg.Data, _msg.Type)
287 }
288 } else {
289 log.Warnf("Received unkown message %v", message)
290 }
291
292 }
293}
294
295// GRPC Endpoints
296
297func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
298 log.WithFields(log.Fields{
299 "onuSerialNumber": onu.SerialNumber,
300 }).Info("Received ActivateOnu call from VOLTHA")
301 msg := Message{
302 Type: OnuIndication,
303 Data: OnuIndicationMessage{
304 OnuSN: onu.SerialNumber,
305 PonPortID: onu.IntfId,
306 OperState: UP,
307 },
308 }
309 o.channel <- msg
310 return new(openolt.Empty) , nil
311}
312
313func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
314 log.Error("DeactivateOnu not implemented")
315 return new(openolt.Empty) , nil
316}
317
318func (o OltDevice) DeleteOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
319 log.Error("DeleteOnu not implemented")
320 return new(openolt.Empty) , nil
321}
322
323func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
324 log.Error("DisableOlt not implemented")
325 return new(openolt.Empty) , nil
326}
327
328func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
329 log.Error("DisablePonIf not implemented")
330 return new(openolt.Empty) , nil
331}
332
333func (o OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
334 log.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
335 o.Enable(stream)
336 return nil
337}
338
339func (o OltDevice) EnablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
340 log.Error("EnablePonIf not implemented")
341 return new(openolt.Empty) , nil
342}
343
344func (o OltDevice) FlowAdd(context.Context, *openolt.Flow) (*openolt.Empty, error) {
345 log.Error("FlowAdd not implemented")
346 return new(openolt.Empty) , nil
347}
348
349func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
350 log.Error("FlowRemove not implemented")
351 return new(openolt.Empty) , nil
352}
353
354func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
355 log.Error("HeartbeatCheck not implemented")
356 return new(openolt.Heartbeat) , nil
357}
358
359func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
360
361 log.WithField("oltId", o.ID).Info("OLT receives GetDeviceInfo call from VOLTHA")
362 devinfo := new(openolt.DeviceInfo)
363 devinfo.Vendor = "BBSim"
364 devinfo.Model = "asfvolt16"
365 devinfo.HardwareVersion = ""
366 devinfo.FirmwareVersion = ""
367 devinfo.Technology = "xgspon"
368 devinfo.PonPorts = 1
369 devinfo.OnuIdStart = 1
370 devinfo.OnuIdEnd = 255
371 devinfo.AllocIdStart = 1024
372 devinfo.AllocIdEnd = 16383
373 devinfo.GemportIdStart = 1024
374 devinfo.GemportIdEnd = 65535
375 devinfo.FlowIdStart = 1
376 devinfo.FlowIdEnd = 16383
377
378 return devinfo, nil
379}
380
381func (o OltDevice) OmciMsgOut(context.Context, *openolt.OmciMsg) (*openolt.Empty, error) {
382 log.Error("OmciMsgOut not implemented")
383 return new(openolt.Empty) , nil
384}
385
386func (o OltDevice) OnuPacketOut(context.Context, *openolt.OnuPacket) (*openolt.Empty, error) {
387 log.Error("OnuPacketOut not implemented")
388 return new(openolt.Empty) , nil
389}
390
391func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
392 log.Error("Reboot not implemented")
393 return new(openolt.Empty) , nil
394}
395
396func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
397 log.Error("ReenableOlt not implemented")
398 return new(openolt.Empty) , nil
399}
400
401func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
402 log.Error("UplinkPacketOut not implemented")
403 return new(openolt.Empty) , nil
404}
405
406func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
407 log.Error("CollectStatistics not implemented")
408 return new(openolt.Empty) , nil
409}
410
411func (o OltDevice) CreateTconts(context context.Context, packet *openolt.Tconts) (*openolt.Empty, error) {
412 log.Error("CreateTconts not implemented")
413 return new(openolt.Empty) , nil
414}
415
416func (o OltDevice) RemoveTconts(context context.Context, packet *openolt.Tconts) (*openolt.Empty, error) {
417 log.Error("RemoveTconts not implemented")
418 return new(openolt.Empty) , nil
419}
420
421func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
422 log.Error("GetOnuInfo not implemented")
423 return new(openolt.OnuIndication) , nil
424}
425
426func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
427 log.Error("GetPonIf not implemented")
428 return new(openolt.IntfIndication) , nil
429}