blob: 7d36bfda421852d1653248ee65ad355cfdf8f34e [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 (
Matteo Scandolo3bc73742019-08-20 14:04:04 -070020 "fmt"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070021 "github.com/google/gopacket/layers"
Matteo Scandolo4747d292019-08-05 11:50:18 -070022 "github.com/looplab/fsm"
Matteo Scandolo075b1892019-10-07 12:11:07 -070023 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070024 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
25 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Matteo Scandoloc559ef12019-08-20 13:24:21 -070026 omci "github.com/opencord/omci-sim"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070027 "github.com/opencord/voltha-protos/go/openolt"
Matteo Scandolo4747d292019-08-05 11:50:18 -070028 log "github.com/sirupsen/logrus"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070029 "net"
Matteo Scandolo4747d292019-08-05 11:50:18 -070030)
31
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070032var onuLogger = log.WithFields(log.Fields{
33 "module": "ONU",
34})
35
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070036type Onu struct {
Matteo Scandolo27428702019-10-11 16:21:16 -070037 ID uint32
38 PonPortID uint32
39 PonPort PonPort
40 STag int
41 CTag int
42 // PortNo comes with flows and it's used when sending packetIndications,
43 // There is one PortNo per UNI Port, for now we're only storing the first one
44 // FIXME add support for multiple UNIs
45 PortNo uint32
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070046 HwAddress net.HardwareAddr
47 InternalState *fsm.FSM
48
49 OperState *fsm.FSM
50 SerialNumber *openolt.SerialNumber
51
52 Channel chan Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
53}
54
55func (o Onu) Sn() string {
56 return onuSnToString(o.SerialNumber)
57}
58
Matteo Scandolo27428702019-10-11 16:21:16 -070059func CreateONU(olt OltDevice, pon PonPort, id uint32, sTag int, cTag int) *Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -070060
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070061 o := Onu{
62 ID: id,
63 PonPortID: pon.ID,
64 PonPort: pon,
65 STag: sTag,
66 CTag: cTag,
67 HwAddress: net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(pon.ID), byte(id)},
Matteo Scandolo27428702019-10-11 16:21:16 -070068 PortNo: 0,
69 Channel: make(chan Message, 2048),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070070 }
71 o.SerialNumber = o.NewSN(olt.ID, pon.ID, o.ID)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070072
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070073 // NOTE this state machine is used to track the operational
74 // state as requested by VOLTHA
75 o.OperState = getOperStateFSM(func(e *fsm.Event) {
76 onuLogger.WithFields(log.Fields{
77 "ID": o.ID,
78 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
79 })
80
81 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
82 o.InternalState = fsm.NewFSM(
83 "created",
84 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -070085 // DEVICE Lifecycle
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070086 {Name: "discover", Src: []string{"created"}, Dst: "discovered"},
Matteo Scandolo10f965c2019-09-24 10:40:46 -070087 {Name: "enable", Src: []string{"discovered", "disabled"}, Dst: "enabled"},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070088 {Name: "receive_eapol_flow", Src: []string{"enabled", "gem_port_added"}, Dst: "eapol_flow_received"},
89 {Name: "add_gem_port", Src: []string{"enabled", "eapol_flow_received"}, Dst: "gem_port_added"},
Matteo Scandolo10f965c2019-09-24 10:40:46 -070090 // NOTE should disabled state be diffente for oper_disabled (emulating an error) and admin_disabled (received a disabled call via VOLTHA)?
91 {Name: "disable", Src: []string{"eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed"}, Dst: "disabled"},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070092 // EAPOL
93 {Name: "start_auth", Src: []string{"eapol_flow_received", "gem_port_added"}, Dst: "auth_started"},
94 {Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
95 {Name: "eap_response_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_response_identity_sent"},
96 {Name: "eap_response_challenge_sent", Src: []string{"eap_response_identity_sent"}, Dst: "eap_response_challenge_sent"},
97 {Name: "eap_response_success_received", Src: []string{"eap_response_challenge_sent"}, Dst: "eap_response_success_received"},
98 {Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent"}, Dst: "auth_failed"},
99 // DHCP
100 {Name: "start_dhcp", Src: []string{"eap_response_success_received"}, Dst: "dhcp_started"},
101 {Name: "dhcp_discovery_sent", Src: []string{"dhcp_started"}, Dst: "dhcp_discovery_sent"},
102 {Name: "dhcp_request_sent", Src: []string{"dhcp_discovery_sent"}, Dst: "dhcp_request_sent"},
103 {Name: "dhcp_ack_received", Src: []string{"dhcp_request_sent"}, Dst: "dhcp_ack_received"},
104 {Name: "dhcp_failed", Src: []string{"dhcp_started", "dhcp_discovery_sent", "dhcp_request_sent"}, Dst: "dhcp_failed"},
105 },
106 fsm.Callbacks{
107 "enter_state": func(e *fsm.Event) {
108 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700109 },
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700110 "enter_enabled": func(event *fsm.Event) {
111 msg := Message{
112 Type: OnuIndication,
113 Data: OnuIndicationMessage{
114 OnuSN: o.SerialNumber,
115 PonPortID: o.PonPortID,
116 OperState: UP,
117 },
118 }
119 o.Channel <- msg
120 },
121 "enter_disabled": func(event *fsm.Event) {
122 msg := Message{
123 Type: OnuIndication,
124 Data: OnuIndicationMessage{
125 OnuSN: o.SerialNumber,
126 PonPortID: o.PonPortID,
127 OperState: DOWN,
128 },
129 }
130 o.Channel <- msg
131 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700132 "enter_auth_started": func(e *fsm.Event) {
133 o.logStateChange(e.Src, e.Dst)
134 msg := Message{
135 Type: StartEAPOL,
136 Data: PacketMessage{
137 PonPortID: o.PonPortID,
138 OnuID: o.ID,
139 },
140 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700141 o.Channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700142 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700143 "enter_auth_failed": func(e *fsm.Event) {
144 onuLogger.WithFields(log.Fields{
145 "OnuId": o.ID,
146 "IntfId": o.PonPortID,
147 "OnuSn": o.Sn(),
148 }).Errorf("ONU failed to authenticate!")
149 },
150 "enter_dhcp_started": func(e *fsm.Event) {
151 msg := Message{
152 Type: StartDHCP,
153 Data: PacketMessage{
154 PonPortID: o.PonPortID,
155 OnuID: o.ID,
156 },
157 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700158 o.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700159 },
160 "enter_dhcp_failed": func(e *fsm.Event) {
161 onuLogger.WithFields(log.Fields{
162 "OnuId": o.ID,
163 "IntfId": o.PonPortID,
164 "OnuSn": o.Sn(),
165 }).Errorf("ONU failed to DHCP!")
166 },
167 },
168 )
Matteo Scandolo27428702019-10-11 16:21:16 -0700169 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700170}
171
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700172func (o Onu) logStateChange(src string, dst string) {
173 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700174 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700175 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700176 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700177 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
178}
179
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700180func (o Onu) processOnuMessages(stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700181 onuLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700182 "onuID": o.ID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700183 "onuSN": o.Sn(),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700184 }).Debug("Started ONU Indication Channel")
185
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700186 for message := range o.Channel {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700187 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700188 "onuID": o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700189 "onuSN": o.Sn(),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700190 "messageType": message.Type,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700191 }).Tracef("Received message on ONU Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700192
193 switch message.Type {
194 case OnuDiscIndication:
195 msg, _ := message.Data.(OnuDiscIndicationMessage)
196 o.sendOnuDiscIndication(msg, stream)
197 case OnuIndication:
198 msg, _ := message.Data.(OnuIndicationMessage)
199 o.sendOnuIndication(msg, stream)
200 case OMCI:
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700201 msg, _ := message.Data.(OmciMessage)
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700202 o.handleOmciMessage(msg, stream)
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700203 case FlowUpdate:
204 msg, _ := message.Data.(OnuFlowUpdateMessage)
205 o.handleFlowUpdate(msg, stream)
206 case StartEAPOL:
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700207 log.Infof("Receive StartEAPOL message on ONU Channel")
Matteo Scandolo27428702019-10-11 16:21:16 -0700208 eapol.SendEapStart(o.ID, o.PonPortID, o.Sn(), o.PortNo, o.HwAddress, o.InternalState, stream)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700209 case StartDHCP:
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700210 log.Infof("Receive StartDHCP message on ONU Channel")
Matteo Scandolo27428702019-10-11 16:21:16 -0700211 // FIXME use id, ponId as SendEapStart
212 dhcp.SendDHCPDiscovery(o.PonPortID, o.ID, o.Sn(), o.PortNo, o.InternalState, o.HwAddress, o.CTag, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700213 case OnuPacketOut:
214 msg, _ := message.Data.(OnuPacketOutMessage)
215 pkt := msg.Packet
216 etherType := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet).EthernetType
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700217
Matteo Scandolo075b1892019-10-07 12:11:07 -0700218 if etherType == layers.EthernetTypeEAPOL {
Matteo Scandolo27428702019-10-11 16:21:16 -0700219 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, o.Sn(), o.PortNo, o.InternalState, msg.Packet, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700220 } else if packetHandlers.IsDhcpPacket(pkt) {
221 // NOTE here we receive packets going from the DHCP Server to the ONU
222 // for now we expect them to be double-tagged, but ideally the should be single tagged
Matteo Scandolo27428702019-10-11 16:21:16 -0700223 dhcp.HandleNextPacket(o.ID, o.PonPortID, o.Sn(), o.PortNo, o.HwAddress, o.CTag, o.InternalState, msg.Packet, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700224 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700225 case DyingGaspIndication:
226 msg, _ := message.Data.(DyingGaspIndicationMessage)
227 o.sendDyingGaspInd(msg, stream)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700228 default:
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700229 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700230 }
231 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700232}
233
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700234func (o Onu) processOmciMessages(stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700235 ch := omci.GetChannel()
236
237 onuLogger.WithFields(log.Fields{
238 "onuID": o.ID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700239 "onuSN": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700240 }).Debug("Started OMCI Indication Channel")
241
242 for message := range ch {
243 switch message.Type {
244 case omci.GemPortAdded:
245 log.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700246 "OnuId": message.Data.OnuId,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700247 "IntfId": message.Data.IntfId,
248 }).Infof("GemPort Added")
249
250 // NOTE if we receive the GemPort but we don't have EAPOL flows
251 // go an intermediate state, otherwise start auth
252 if o.InternalState.Is("enabled") {
253 if err := o.InternalState.Event("add_gem_port"); err != nil {
254 log.Errorf("Can't go to gem_port_added: %v", err)
255 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700256 } else if o.InternalState.Is("eapol_flow_received") {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700257 if err := o.InternalState.Event("start_auth"); err != nil {
258 log.Errorf("Can't go to auth_started: %v", err)
259 }
260 }
261 }
262 }
263}
264
Matteo Scandolo4747d292019-08-05 11:50:18 -0700265func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
266
267 sn := new(openolt.SerialNumber)
268
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700269 //sn = new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700270 sn.VendorId = []byte("BBSM")
271 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
272
273 return sn
274}
275
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700276// NOTE handle_/process methods can change the ONU internal state as they are receiving messages
277// send method should not change the ONU state
278
279func (o Onu) sendDyingGaspInd(msg DyingGaspIndicationMessage, stream openolt.Openolt_EnableIndicationServer) error {
280 alarmData := &openolt.AlarmIndication_DyingGaspInd{
281 DyingGaspInd: &openolt.DyingGaspIndication{
282 IntfId: msg.PonPortID,
283 OnuId: msg.OnuID,
284 Status: "on",
285 },
286 }
287 data := &openolt.Indication_AlarmInd{AlarmInd: &openolt.AlarmIndication{Data: alarmData}}
288
289 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
290 onuLogger.Errorf("Failed to send DyingGaspInd : %v", err)
291 return err
292 }
293 onuLogger.WithFields(log.Fields{
294 "IntfId": msg.PonPortID,
295 "OnuSn": o.Sn(),
296 "OnuId": msg.OnuID,
297 }).Info("sendDyingGaspInd")
298 return nil
299}
300
Matteo Scandolo4747d292019-08-05 11:50:18 -0700301func (o Onu) sendOnuDiscIndication(msg OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
302 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700303 IntfId: msg.Onu.PonPortID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700304 SerialNumber: msg.Onu.SerialNumber,
305 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700306
Matteo Scandolo4747d292019-08-05 11:50:18 -0700307 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700308 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700309 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700310
311 if err := o.InternalState.Event("discover"); err != nil {
312 oltLogger.WithFields(log.Fields{
313 "IntfId": o.PonPortID,
314 "OnuSn": o.Sn(),
315 "OnuId": o.ID,
316 }).Infof("Failed to transition ONU to discovered state: %s", err.Error())
317 }
318
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700319 onuLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700320 "IntfId": msg.Onu.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700321 "OnuSn": msg.Onu.Sn(),
322 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700323 }).Debug("Sent Indication_OnuDiscInd")
324}
325
326func (o Onu) sendOnuIndication(msg OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
327 // NOTE voltha returns an ID, but if we use that ID then it complains:
328 // expected_onu_id: 1, received_onu_id: 1024, event: ONU-id-mismatch, can happen if both voltha and the olt rebooted
329 // so we're using the internal ID that is 1
330 // o.ID = msg.OnuID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700331
332 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700333 IntfId: o.PonPortID,
334 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700335 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700336 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700337 SerialNumber: o.SerialNumber,
338 }}
339 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700340 // TODO do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700341 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700342 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700343 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700344 "IntfId": o.PonPortID,
345 "OnuId": o.ID,
346 "OperState": msg.OperState.String(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700347 "AdminState": msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700348 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700349 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700350
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700351}
352
353func (o Onu) handleOmciMessage(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
354
355 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700356 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700357 "SerialNumber": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700358 "omciPacket": msg.omciMsg.Pkt,
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700359 }).Tracef("Received OMCI message")
360
361 var omciInd openolt.OmciIndication
362 respPkt, err := omci.OmciSim(o.PonPortID, o.ID, HexDecode(msg.omciMsg.Pkt))
363 if err != nil {
Matteo Scandolo27428702019-10-11 16:21:16 -0700364 onuLogger.WithFields(log.Fields{
365 "IntfId": o.PonPortID,
366 "SerialNumber": o.Sn(),
367 "omciPacket": omciInd.Pkt,
368 "msg": msg,
369 }).Errorf("Error handling OMCI message %v", msg)
370 return
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700371 }
372
373 omciInd.IntfId = o.PonPortID
374 omciInd.OnuId = o.ID
375 omciInd.Pkt = respPkt
376
377 omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
378 if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
Matteo Scandolo27428702019-10-11 16:21:16 -0700379 onuLogger.WithFields(log.Fields{
380 "IntfId": o.PonPortID,
381 "SerialNumber": o.Sn(),
382 "omciPacket": omciInd.Pkt,
383 "msg": msg,
384 }).Errorf("send omci indication failed: %v", err)
385 return
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700386 }
387 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700388 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700389 "SerialNumber": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700390 "omciPacket": omciInd.Pkt,
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700391 }).Tracef("Sent OMCI message")
392}
393
Matteo Scandolo27428702019-10-11 16:21:16 -0700394func (o *Onu) storePortNumber(portNo uint32) {
395 // FIXME this is a workaround to always use the SN-1 entry in sadis,
396 // we need to add support for multiple UNIs
397 // the action plan is:
398 // - refactor the omci-sim library to use https://github.com/cboling/omci instead of canned messages
399 // - change the library so that it reports a single UNI and remove this workaroung
400 // - add support for multiple UNIs in BBSim
401 if portNo < o.PortNo {
402 o.PortNo = portNo
403 }
404}
405
406func (o *Onu) handleFlowUpdate(msg OnuFlowUpdateMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700407 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700408 "DstPort": msg.Flow.Classifier.DstPort,
409 "EthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
410 "FlowId": msg.Flow.FlowId,
411 "FlowType": msg.Flow.FlowType,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700412 "InnerVlan": msg.Flow.Classifier.IVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700413 "IntfId": msg.Flow.AccessIntfId,
414 "IpProto": msg.Flow.Classifier.IpProto,
415 "OnuId": msg.Flow.OnuId,
416 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700417 "OuterVlan": msg.Flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700418 "PortNo": msg.Flow.PortNo,
419 "SrcPort": msg.Flow.Classifier.SrcPort,
420 "UniID": msg.Flow.UniId,
421 }).Debug("ONU receives Flow")
422
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700423 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo27428702019-10-11 16:21:16 -0700424 // NOTE storing the PortNO, it's needed when sending PacketIndications
425 if o.PortNo == 0 {
426 o.storePortNumber(uint32(msg.Flow.PortNo))
427 }
428
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700429 // NOTE if we receive the EAPOL flows but we don't have GemPorts
430 // go an intermediate state, otherwise start auth
431 if o.InternalState.Is("enabled") {
432 if err := o.InternalState.Event("receive_eapol_flow"); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700433 log.Warnf("Can't go to eapol_flow_received: %v", err)
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700434 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700435 } else if o.InternalState.Is("gem_port_added") {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700436 if err := o.InternalState.Event("start_auth"); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700437 log.Warnf("Can't go to auth_started: %v", err)
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700438 }
439 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700440 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
441 msg.Flow.Classifier.SrcPort == uint32(68) &&
442 msg.Flow.Classifier.DstPort == uint32(67) {
443 // NOTE we are receiving mulitple DHCP flows but we shouldn't call the transition multiple times
444 if err := o.InternalState.Event("start_dhcp"); err != nil {
445 log.Warnf("Can't go to dhcp_started: %v", err)
446 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700447 }
448}
449
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700450// HexDecode converts the hex encoding to binary
451func HexDecode(pkt []byte) []byte {
452 p := make([]byte, len(pkt)/2)
453 for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
454 // Go figure this ;)
455 u := (pkt[i] & 15) + (pkt[i]>>6)*9
456 l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
457 p[j] = u<<4 + l
458 }
459 onuLogger.Tracef("Omci decoded: %x.", p)
460 return p
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700461}