blob: 6b879cc8c6bd6f91b213f0579d213e9af6c20db4 [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 Scandolo40e067f2019-10-16 16:59:41 -070020 "context"
Matteo Scandolo99f18462019-10-28 14:14:28 -070021 "errors"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070022 "fmt"
Zdravko Bozakov681364d2019-11-10 14:28:46 +010023 "net"
24
25 "time"
26
Matteo Scandolo40e067f2019-10-16 16:59:41 -070027 "github.com/cboling/omci"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070028 "github.com/google/gopacket/layers"
Matteo Scandolo4747d292019-08-05 11:50:18 -070029 "github.com/looplab/fsm"
Matteo Scandolo075b1892019-10-07 12:11:07 -070030 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070031 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
32 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
Arjun E K57a7fcb2020-01-30 06:44:45 +000033 "github.com/opencord/bbsim/internal/bbsim/responders/igmp"
Matteo Scandolo40e067f2019-10-16 16:59:41 -070034 "github.com/opencord/bbsim/internal/common"
35 omcilib "github.com/opencord/bbsim/internal/common/omci"
36 omcisim "github.com/opencord/omci-sim"
Matteo Scandolo3de9de02019-11-14 13:40:03 -080037 "github.com/opencord/voltha-protos/v2/go/openolt"
Matteo Scandolod74abba2020-04-16 16:36:44 -070038 "github.com/opencord/voltha-protos/v2/go/tech_profile"
Matteo Scandolo4747d292019-08-05 11:50:18 -070039 log "github.com/sirupsen/logrus"
40)
41
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070042var onuLogger = log.WithFields(log.Fields{
43 "module": "ONU",
44})
45
Pragya Arya8bdb4532020-03-02 17:08:09 +053046type FlowKey struct {
47 ID uint32
48 Direction string
49}
50
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070051type Onu struct {
Matteo Scandoloe811ae92019-12-10 17:50:14 -080052 ID uint32
53 PonPortID uint32
54 PonPort PonPort
55 STag int
56 CTag int
57 Auth bool // automatically start EAPOL if set to true
58 Dhcp bool // automatically start DHCP if set to true
59 HwAddress net.HardwareAddr
60 InternalState *fsm.FSM
Pragya Arya2225f202020-01-29 18:05:01 +053061 DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
62 DiscoveryDelay time.Duration // this is the time to send the first Discovery Indication
Matteo Scandoloe811ae92019-12-10 17:50:14 -080063
64 // ONU State
Matteo Scandolo27428702019-10-11 16:21:16 -070065 // PortNo comes with flows and it's used when sending packetIndications,
66 // There is one PortNo per UNI Port, for now we're only storing the first one
Matteo Scandolo47ef64b2020-04-20 14:16:07 -070067 // FIXME add support for multiple UNIs (each UNI has a different PortNo)
Matteo Scandolo5ff80082019-12-20 13:20:57 -080068 PortNo uint32
69 GemPortAdded bool
70 EapolFlowReceived bool
71 DhcpFlowReceived bool
72 Flows []FlowKey
Matteo Scandolo99f18462019-10-28 14:14:28 -070073
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070074 OperState *fsm.FSM
75 SerialNumber *openolt.SerialNumber
76
Matteo Scandolo5ff80082019-12-20 13:20:57 -080077 Channel chan Message // this Channel is to track state changes OMCI messages, EAPOL and DHCP packets
78 GemPortChannels []chan bool // this channels are used to notify everyone that is interested that a GemPort has been added
Matteo Scandolo40e067f2019-10-16 16:59:41 -070079
80 // OMCI params
81 tid uint16
82 hpTid uint16
83 seqNumber uint16
84 HasGemPort bool
85
Anand S Katti09541352020-01-29 15:54:01 +053086 DoneChannel chan bool // this channel is used to signal once the onu is complete (when the struct is used by BBR)
87 TrafficSchedulers *tech_profile.TrafficSchedulers
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070088}
89
Matteo Scandolo99f18462019-10-28 14:14:28 -070090func (o *Onu) Sn() string {
Matteo Scandolo40e067f2019-10-16 16:59:41 -070091 return common.OnuSnToString(o.SerialNumber)
Matteo Scandolo86e8ce62019-10-11 12:03:10 -070092}
93
Matteo Scandolo5ff80082019-12-20 13:20:57 -080094func (o *Onu) GetGemPortChan() chan bool {
95 listener := make(chan bool, 1)
96 o.GemPortChannels = append(o.GemPortChannels, listener)
97 return listener
98}
99
Pragya Arya2225f202020-01-29 18:05:01 +0530100func CreateONU(olt *OltDevice, pon PonPort, id uint32, sTag int, cTag int, auth bool, dhcp bool, delay time.Duration, isMock bool) *Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700101
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700102 o := Onu{
Pragya Arya2225f202020-01-29 18:05:01 +0530103 ID: 0,
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800104 PonPortID: pon.ID,
105 PonPort: pon,
106 STag: sTag,
107 CTag: cTag,
108 Auth: auth,
109 Dhcp: dhcp,
Matteo Scandolo378b8c92020-04-16 14:34:22 -0700110 HwAddress: net.HardwareAddr{0x2e, 0x60, 0x70, byte(olt.ID), byte(pon.ID), byte(id)},
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800111 PortNo: 0,
112 tid: 0x1,
113 hpTid: 0x8000,
114 seqNumber: 0,
115 DoneChannel: make(chan bool, 1),
116 DhcpFlowReceived: false,
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800117 EapolFlowReceived: false,
118 GemPortAdded: false,
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800119 DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
Pragya Arya8bdb4532020-03-02 17:08:09 +0530120 Flows: []FlowKey{},
Pragya Arya2225f202020-01-29 18:05:01 +0530121 DiscoveryDelay: delay,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700122 }
Pragya Arya2225f202020-01-29 18:05:01 +0530123 o.SerialNumber = o.NewSN(olt.ID, pon.ID, id)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700124
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700125 // NOTE this state machine is used to track the operational
126 // state as requested by VOLTHA
127 o.OperState = getOperStateFSM(func(e *fsm.Event) {
128 onuLogger.WithFields(log.Fields{
129 "ID": o.ID,
130 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
131 })
132
133 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
134 o.InternalState = fsm.NewFSM(
135 "created",
136 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700137 // DEVICE Lifecycle
Hardik Windlassad790cb2020-06-17 21:26:22 +0530138 {Name: "initialize", Src: []string{"created", "disabled", "pon_disabled"}, Dst: "initialized"},
139 {Name: "discover", Src: []string{"initialized"}, Dst: "discovered"},
140 {Name: "enable", Src: []string{"discovered", "pon_disabled"}, Dst: "enabled"},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700141 {Name: "receive_eapol_flow", Src: []string{"enabled", "gem_port_added"}, Dst: "eapol_flow_received"},
142 {Name: "add_gem_port", Src: []string{"enabled", "eapol_flow_received"}, Dst: "gem_port_added"},
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100143 // NOTE should disabled state be different for oper_disabled (emulating an error) and admin_disabled (received a disabled call via VOLTHA)?
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800144 {Name: "disable", Src: []string{"enabled", "eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed", "pon_disabled"}, Dst: "disabled"},
Pragya Arya6a708d62020-01-01 17:17:20 +0530145 // ONU state when PON port is disabled but ONU is power ON(more states should be added in src?)
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800146 {Name: "pon_disabled", Src: []string{"enabled", "eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed"}, Dst: "pon_disabled"},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700147 // EAPOL
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800148 {Name: "start_auth", Src: []string{"enabled", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent", "eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed", "igmp_join_started", "igmp_left", "igmp_join_error"}, Dst: "auth_started"},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700149 {Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
150 {Name: "eap_response_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_response_identity_sent"},
151 {Name: "eap_response_challenge_sent", Src: []string{"eap_response_identity_sent"}, Dst: "eap_response_challenge_sent"},
152 {Name: "eap_response_success_received", Src: []string{"eap_response_challenge_sent"}, Dst: "eap_response_success_received"},
153 {Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent"}, Dst: "auth_failed"},
154 // DHCP
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800155 {Name: "start_dhcp", Src: []string{"enabled", "eap_response_success_received", "dhcp_discovery_sent", "dhcp_request_sent", "dhcp_ack_received", "dhcp_failed", "igmp_join_started", "igmp_left", "igmp_join_error"}, Dst: "dhcp_started"},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700156 {Name: "dhcp_discovery_sent", Src: []string{"dhcp_started"}, Dst: "dhcp_discovery_sent"},
157 {Name: "dhcp_request_sent", Src: []string{"dhcp_discovery_sent"}, Dst: "dhcp_request_sent"},
158 {Name: "dhcp_ack_received", Src: []string{"dhcp_request_sent"}, Dst: "dhcp_ack_received"},
159 {Name: "dhcp_failed", Src: []string{"dhcp_started", "dhcp_discovery_sent", "dhcp_request_sent"}, Dst: "dhcp_failed"},
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700160 // BBR States
161 // TODO add start OMCI state
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100162 {Name: "send_eapol_flow", Src: []string{"initialized"}, Dst: "eapol_flow_sent"},
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700163 {Name: "send_dhcp_flow", Src: []string{"eapol_flow_sent"}, Dst: "dhcp_flow_sent"},
Arjun E K57a7fcb2020-01-30 06:44:45 +0000164 // IGMP
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800165 {Name: "igmp_join_start", Src: []string{"eap_response_success_received", "dhcp_ack_received", "igmp_left", "igmp_join_error", "igmp_join_started"}, Dst: "igmp_join_started"},
166 {Name: "igmp_join_startv3", Src: []string{"eap_response_success_received", "dhcp_ack_received", "igmp_left", "igmp_join_error", "igmp_join_started"}, Dst: "igmp_join_started"},
Shubham Sharmabd4b6572020-02-12 13:00:44 +0000167 {Name: "igmp_join_error", Src: []string{"igmp_join_started"}, Dst: "igmp_join_error"},
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800168 {Name: "igmp_leave", Src: []string{"igmp_join_started", "eap_response_success_received", "dhcp_ack_received"}, Dst: "igmp_left"},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700169 },
170 fsm.Callbacks{
171 "enter_state": func(e *fsm.Event) {
172 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700173 },
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100174 "enter_initialized": func(e *fsm.Event) {
175 // create new channel for ProcessOnuMessages Go routine
176 o.Channel = make(chan Message, 2048)
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800177
178 if err := o.OperState.Event("enable"); err != nil {
179 onuLogger.WithFields(log.Fields{
180 "OnuId": o.ID,
181 "IntfId": o.PonPortID,
182 "OnuSn": o.Sn(),
183 }).Errorf("Cannot change ONU OperState to up: %s", err.Error())
184 }
185
Pragya Arya1cbefa42020-01-13 12:15:29 +0530186 if !isMock {
187 // start ProcessOnuMessages Go routine
188 go o.ProcessOnuMessages(olt.enableContext, *olt.OpenoltStream, nil)
189 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100190 },
191 "enter_discovered": func(e *fsm.Event) {
192 msg := Message{
193 Type: OnuDiscIndication,
194 Data: OnuDiscIndicationMessage{
195 Onu: &o,
196 OperState: UP,
197 },
198 }
199 o.Channel <- msg
200 },
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700201 "enter_enabled": func(event *fsm.Event) {
202 msg := Message{
203 Type: OnuIndication,
204 Data: OnuIndicationMessage{
205 OnuSN: o.SerialNumber,
206 PonPortID: o.PonPortID,
207 OperState: UP,
208 },
209 }
210 o.Channel <- msg
211 },
212 "enter_disabled": func(event *fsm.Event) {
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700213
214 // clean the ONU state
215 o.DhcpFlowReceived = false
216 o.PortNo = 0
217 o.Flows = []FlowKey{}
218
219 // set the OpenState to disabled
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800220 if err := o.OperState.Event("disable"); err != nil {
221 onuLogger.WithFields(log.Fields{
222 "OnuId": o.ID,
223 "IntfId": o.PonPortID,
224 "OnuSn": o.Sn(),
225 }).Errorf("Cannot change ONU OperState to down: %s", err.Error())
226 }
Matteo Scandolo47ef64b2020-04-20 14:16:07 -0700227
228 // send the OnuIndication DOWN event
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700229 msg := Message{
230 Type: OnuIndication,
231 Data: OnuIndicationMessage{
232 OnuSN: o.SerialNumber,
233 PonPortID: o.PonPortID,
234 OperState: DOWN,
235 },
236 }
237 o.Channel <- msg
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100238 // terminate the ONU's ProcessOnuMessages Go routine
239 close(o.Channel)
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700240 },
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800241 "before_start_auth": func(e *fsm.Event) {
242 if o.EapolFlowReceived == false {
243 e.Cancel(errors.New("cannot-go-to-auth-started-as-eapol-flow-is-missing"))
244 return
245 }
246 if o.GemPortAdded == false {
247 e.Cancel(errors.New("cannot-go-to-auth-started-as-gemport-is-missing"))
248 return
249 }
250 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700251 "enter_auth_started": func(e *fsm.Event) {
252 o.logStateChange(e.Src, e.Dst)
253 msg := Message{
254 Type: StartEAPOL,
255 Data: PacketMessage{
256 PonPortID: o.PonPortID,
257 OnuID: o.ID,
258 },
259 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700260 o.Channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700261 },
Pragya Arya324337e2020-02-20 14:35:08 +0530262 "enter_eap_response_success_received": func(e *fsm.Event) {
263 publishEvent("ONU-authentication-done", int32(o.PonPortID), int32(o.ID), o.Sn())
264 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700265 "enter_auth_failed": func(e *fsm.Event) {
266 onuLogger.WithFields(log.Fields{
267 "OnuId": o.ID,
268 "IntfId": o.PonPortID,
269 "OnuSn": o.Sn(),
270 }).Errorf("ONU failed to authenticate!")
271 },
Matteo Scandolo99f18462019-10-28 14:14:28 -0700272 "before_start_dhcp": func(e *fsm.Event) {
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800273
274 // we allow transition from eanbled to dhcp_started only if auth was set to false
275 if o.InternalState.Current() == "enabled" && o.Auth {
276 e.Cancel(errors.New("cannot-go-to-dhcp-started-as-authentication-is-required"))
277 return
278 }
279
Matteo Scandolo99f18462019-10-28 14:14:28 -0700280 if o.DhcpFlowReceived == false {
281 e.Cancel(errors.New("cannot-go-to-dhcp-started-as-dhcp-flow-is-missing"))
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800282 return
283 }
284
285 if o.GemPortAdded == false {
286 e.Cancel(errors.New("cannot-go-to-dhcp-started-as-gemport-is-missing"))
287 return
Matteo Scandolo99f18462019-10-28 14:14:28 -0700288 }
289 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700290 "enter_dhcp_started": func(e *fsm.Event) {
291 msg := Message{
292 Type: StartDHCP,
293 Data: PacketMessage{
294 PonPortID: o.PonPortID,
295 OnuID: o.ID,
296 },
297 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700298 o.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700299 },
Pragya Arya324337e2020-02-20 14:35:08 +0530300 "enter_dhcp_ack_received": func(e *fsm.Event) {
301 publishEvent("ONU-DHCP-ACK-received", int32(o.PonPortID), int32(o.ID), o.Sn())
302 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700303 "enter_dhcp_failed": func(e *fsm.Event) {
304 onuLogger.WithFields(log.Fields{
305 "OnuId": o.ID,
306 "IntfId": o.PonPortID,
307 "OnuSn": o.Sn(),
308 }).Errorf("ONU failed to DHCP!")
309 },
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700310 "enter_eapol_flow_sent": func(e *fsm.Event) {
311 msg := Message{
312 Type: SendEapolFlow,
313 }
314 o.Channel <- msg
315 },
316 "enter_dhcp_flow_sent": func(e *fsm.Event) {
317 msg := Message{
318 Type: SendDhcpFlow,
319 }
320 o.Channel <- msg
321 },
Arjun E K57a7fcb2020-01-30 06:44:45 +0000322 "igmp_join_start": func(e *fsm.Event) {
323 msg := Message{
324 Type: IGMPMembershipReportV2,
325 }
326 o.Channel <- msg
327 },
328 "igmp_leave": func(e *fsm.Event) {
329 msg := Message{
330 Type: IGMPLeaveGroup}
331 o.Channel <- msg
332 },
Anand S Katti09541352020-01-29 15:54:01 +0530333 "igmp_join_startv3": func(e *fsm.Event) {
334 msg := Message{
335 Type: IGMPMembershipReportV3,
336 }
337 o.Channel <- msg
338 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700339 },
340 )
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100341
Matteo Scandolo27428702019-10-11 16:21:16 -0700342 return &o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700343}
344
William Kurkian0418bc82019-11-06 12:16:24 -0500345func (o *Onu) logStateChange(src string, dst string) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700346 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700347 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700348 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700349 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700350 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
351}
352
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100353// ProcessOnuMessages starts indication channel for each ONU
David Bainbridge103cf022019-12-16 20:11:35 +0000354func (o *Onu) ProcessOnuMessages(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700355 onuLogger.WithFields(log.Fields{
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100356 "onuID": o.ID,
357 "onuSN": o.Sn(),
358 "ponPort": o.PonPortID,
359 }).Debug("Starting ONU Indication Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700360
David Bainbridge103cf022019-12-16 20:11:35 +0000361loop:
362 for {
363 select {
364 case <-ctx.Done():
365 onuLogger.WithFields(log.Fields{
366 "onuID": o.ID,
367 "onuSN": o.Sn(),
368 }).Tracef("ONU message handling canceled via context")
369 break loop
370 case message, ok := <-o.Channel:
371 if !ok || ctx.Err() != nil {
372 onuLogger.WithFields(log.Fields{
373 "onuID": o.ID,
374 "onuSN": o.Sn(),
375 }).Tracef("ONU message handling canceled via channel close")
376 break loop
Matteo Scandolo075b1892019-10-07 12:11:07 -0700377 }
David Bainbridge103cf022019-12-16 20:11:35 +0000378 onuLogger.WithFields(log.Fields{
379 "onuID": o.ID,
380 "onuSN": o.Sn(),
381 "messageType": message.Type,
382 }).Tracef("Received message on ONU Channel")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700383
David Bainbridge103cf022019-12-16 20:11:35 +0000384 switch message.Type {
385 case OnuDiscIndication:
386 msg, _ := message.Data.(OnuDiscIndicationMessage)
387 // NOTE we need to slow down and send ONU Discovery Indication in batches to better emulate a real scenario
Pragya Arya2225f202020-01-29 18:05:01 +0530388 time.Sleep(o.DiscoveryDelay)
David Bainbridge103cf022019-12-16 20:11:35 +0000389 o.sendOnuDiscIndication(msg, stream)
390 case OnuIndication:
391 msg, _ := message.Data.(OnuIndicationMessage)
392 o.sendOnuIndication(msg, stream)
393 case OMCI:
394 msg, _ := message.Data.(OmciMessage)
395 o.handleOmciMessage(msg, stream)
396 case FlowUpdate:
397 msg, _ := message.Data.(OnuFlowUpdateMessage)
398 o.handleFlowUpdate(msg)
399 case StartEAPOL:
400 log.Infof("Receive StartEAPOL message on ONU Channel")
401 eapol.SendEapStart(o.ID, o.PonPortID, o.Sn(), o.PortNo, o.HwAddress, o.InternalState, stream)
402 case StartDHCP:
403 log.Infof("Receive StartDHCP message on ONU Channel")
404 // FIXME use id, ponId as SendEapStart
Matteo Scandolo378b8c92020-04-16 14:34:22 -0700405 dhcp.SendDHCPDiscovery(o.PonPort.Olt.ID, o.PonPortID, o.ID, o.Sn(), o.PortNo, o.InternalState, o.HwAddress, o.CTag, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000406 case OnuPacketOut:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700407
David Bainbridge103cf022019-12-16 20:11:35 +0000408 msg, _ := message.Data.(OnuPacketMessage)
409
410 log.WithFields(log.Fields{
411 "IntfId": msg.IntfId,
412 "OnuId": msg.OnuId,
413 "pktType": msg.Type,
414 }).Trace("Received OnuPacketOut Message")
415
416 if msg.Type == packetHandlers.EAPOL {
417 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, o.Sn(), o.PortNo, o.InternalState, msg.Packet, stream, client)
418 } else if msg.Type == packetHandlers.DHCP {
419 // NOTE here we receive packets going from the DHCP Server to the ONU
420 // for now we expect them to be double-tagged, but ideally the should be single tagged
Matteo Scandolo378b8c92020-04-16 14:34:22 -0700421 dhcp.HandleNextPacket(o.PonPort.Olt.ID, o.ID, o.PonPortID, o.Sn(), o.PortNo, o.HwAddress, o.CTag, o.InternalState, msg.Packet, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000422 }
423 case OnuPacketIn:
424 // NOTE we only receive BBR packets here.
425 // Eapol.HandleNextPacket can handle both BBSim and BBr cases so the call is the same
426 // in the DHCP case VOLTHA only act as a proxy, the behaviour is completely different thus we have a dhcp.HandleNextBbrPacket
427 msg, _ := message.Data.(OnuPacketMessage)
428
429 log.WithFields(log.Fields{
430 "IntfId": msg.IntfId,
431 "OnuId": msg.OnuId,
432 "pktType": msg.Type,
433 }).Trace("Received OnuPacketIn Message")
434
435 if msg.Type == packetHandlers.EAPOL {
436 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, o.Sn(), o.PortNo, o.InternalState, msg.Packet, stream, client)
437 } else if msg.Type == packetHandlers.DHCP {
438 dhcp.HandleNextBbrPacket(o.ID, o.PonPortID, o.Sn(), o.STag, o.HwAddress, o.DoneChannel, msg.Packet, client)
439 }
David Bainbridge103cf022019-12-16 20:11:35 +0000440 case OmciIndication:
441 msg, _ := message.Data.(OmciIndicationMessage)
442 o.handleOmci(msg, client)
443 case SendEapolFlow:
444 o.sendEapolFlow(client)
445 case SendDhcpFlow:
446 o.sendDhcpFlow(client)
Arjun E K57a7fcb2020-01-30 06:44:45 +0000447 case IGMPMembershipReportV2:
448 log.Infof("Recieved IGMPMembershipReportV2 message on ONU channel")
449 igmp.SendIGMPMembershipReportV2(o.PonPortID, o.ID, o.Sn(), o.PortNo, o.HwAddress, stream)
450 case IGMPLeaveGroup:
451 log.Infof("Recieved IGMPLeaveGroupV2 message on ONU channel")
452 igmp.SendIGMPLeaveGroupV2(o.PonPortID, o.ID, o.Sn(), o.PortNo, o.HwAddress, stream)
Anand S Katti09541352020-01-29 15:54:01 +0530453 case IGMPMembershipReportV3:
454 log.Infof("Recieved IGMPMembershipReportV3 message on ONU channel")
455 igmp.SendIGMPMembershipReportV3(o.PonPortID, o.ID, o.Sn(), o.PortNo, o.HwAddress, stream)
David Bainbridge103cf022019-12-16 20:11:35 +0000456 default:
457 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700458 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700459 }
460 }
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100461 onuLogger.WithFields(log.Fields{
462 "onuID": o.ID,
463 "onuSN": o.Sn(),
464 }).Debug("Stopped handling ONU Indication Channel")
Matteo Scandolo4747d292019-08-05 11:50:18 -0700465}
466
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800467func (o *Onu) processOmciMessage(message omcisim.OmciChMessage, stream openolt.Openolt_EnableIndicationServer) {
William Kurkian9dadc5b2019-10-22 13:51:57 -0400468 switch message.Type {
Matteo Scandolodf3f85d2020-01-15 12:50:48 -0800469 case omcisim.UniLinkUp, omcisim.UniLinkDown:
470 onuLogger.WithFields(log.Fields{
471 "OnuId": message.Data.OnuId,
472 "IntfId": message.Data.IntfId,
473 "Type": message.Type,
474 }).Infof("UNI Link Alarm")
475 // TODO send to OLT
476
477 omciInd := openolt.OmciIndication{
478 IntfId: message.Data.IntfId,
479 OnuId: message.Data.OnuId,
480 Pkt: message.Packet,
481 }
482
483 omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
484 if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
485 onuLogger.WithFields(log.Fields{
486 "IntfId": o.PonPortID,
487 "SerialNumber": o.Sn(),
488 "Type": message.Type,
489 "omciPacket": omciInd.Pkt,
490 }).Errorf("Failed to send UNI Link Alarm: %v", err)
491 return
492 }
493
494 onuLogger.WithFields(log.Fields{
495 "IntfId": o.PonPortID,
496 "SerialNumber": o.Sn(),
497 "Type": message.Type,
498 "omciPacket": omciInd.Pkt,
499 }).Info("UNI Link alarm sent")
500
William Kurkian9dadc5b2019-10-22 13:51:57 -0400501 case omcisim.GemPortAdded:
502 log.WithFields(log.Fields{
503 "OnuId": message.Data.OnuId,
504 "IntfId": message.Data.IntfId,
Matteo Scandolod74abba2020-04-16 16:36:44 -0700505 "OnuSn": o.Sn(),
William Kurkian9dadc5b2019-10-22 13:51:57 -0400506 }).Infof("GemPort Added")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700507
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800508 o.GemPortAdded = true
509
510 // broadcast the change to all listeners
511 // and close the channels as once the GemPort is set
512 // it won't change anymore
513 for _, ch := range o.GemPortChannels {
514 ch <- true
515 close(ch)
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700516 }
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800517 o.GemPortChannels = []chan bool{}
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700518 }
519}
520
Zdravko Bozakov681364d2019-11-10 14:28:46 +0100521func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700522
523 sn := new(openolt.SerialNumber)
524
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700525 //sn = new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700526 sn.VendorId = []byte("BBSM")
527 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
528
529 return sn
530}
531
William Kurkian0418bc82019-11-06 12:16:24 -0500532func (o *Onu) sendOnuDiscIndication(msg OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700533 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700534 IntfId: msg.Onu.PonPortID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700535 SerialNumber: msg.Onu.SerialNumber,
536 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700537
Matteo Scandolo4747d292019-08-05 11:50:18 -0700538 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700539 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo99f18462019-10-28 14:14:28 -0700540 return
Matteo Scandolo4747d292019-08-05 11:50:18 -0700541 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700542
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700543 onuLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700544 "IntfId": msg.Onu.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700545 "OnuSn": msg.Onu.Sn(),
546 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700547 }).Debug("Sent Indication_OnuDiscInd")
Pragya Arya324337e2020-02-20 14:35:08 +0530548 publishEvent("ONU-discovery-indication-sent", int32(msg.Onu.PonPortID), int32(o.ID), msg.Onu.Sn())
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800549
550 // after DiscoveryRetryDelay check if the state is the same and in case send a new OnuDiscIndication
551 go func(delay time.Duration) {
Matteo Scandolo569e7172019-12-20 11:51:51 -0800552 time.Sleep(delay)
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800553 if o.InternalState.Current() == "discovered" {
Matteo Scandoloe811ae92019-12-10 17:50:14 -0800554 o.sendOnuDiscIndication(msg, stream)
555 }
556 }(o.DiscoveryRetryDelay)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700557}
558
William Kurkian0418bc82019-11-06 12:16:24 -0500559func (o *Onu) sendOnuIndication(msg OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4747d292019-08-05 11:50:18 -0700560 // NOTE voltha returns an ID, but if we use that ID then it complains:
561 // expected_onu_id: 1, received_onu_id: 1024, event: ONU-id-mismatch, can happen if both voltha and the olt rebooted
562 // so we're using the internal ID that is 1
563 // o.ID = msg.OnuID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700564
565 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700566 IntfId: o.PonPortID,
567 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700568 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700569 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700570 SerialNumber: o.SerialNumber,
571 }}
572 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800573 // NOTE do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700574 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700575 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700576 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700577 "IntfId": o.PonPortID,
578 "OnuId": o.ID,
579 "OperState": msg.OperState.String(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700580 "AdminState": msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700581 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700582 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700583
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700584}
585
Pragya Arya324337e2020-02-20 14:35:08 +0530586func (o *Onu) publishOmciEvent(msg OmciMessage) {
587 if olt.PublishEvents {
588 _, _, msgType, _, _, _, err := omcisim.ParsePkt(HexDecode(msg.omciMsg.Pkt))
589 if err != nil {
590 log.Errorf("error in getting msgType %v", err)
591 return
592 }
593 if msgType == omcisim.MibUpload {
594 o.seqNumber = 0
595 publishEvent("MIB-upload-received", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
596 } else if msgType == omcisim.MibUploadNext {
597 o.seqNumber++
598 if o.seqNumber > 290 {
599 publishEvent("MIB-upload-done", int32(o.PonPortID), int32(o.ID), common.OnuSnToString(o.SerialNumber))
600 }
601 }
602 }
603}
604
Scott Bakerb90c4312020-03-12 21:33:25 -0700605// Create a TestResponse packet and send it
606func (o *Onu) sendTestResult(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) error {
607 resp, err := omcilib.BuildTestResult(HexDecode(msg.omciMsg.Pkt))
608 if err != nil {
609 return err
610 }
611
612 var omciInd openolt.OmciIndication
613 omciInd.IntfId = o.PonPortID
614 omciInd.OnuId = o.ID
615 omciInd.Pkt = resp
616
617 omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
618 if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
619 onuLogger.WithFields(log.Fields{
620 "IntfId": o.PonPortID,
621 "SerialNumber": o.Sn(),
622 "omciPacket": omciInd.Pkt,
623 "msg": msg,
624 }).Errorf("send TestResult omcisim indication failed: %v", err)
625 return err
626 }
627 onuLogger.WithFields(log.Fields{
628 "IntfId": o.PonPortID,
629 "SerialNumber": o.Sn(),
630 "omciPacket": omciInd.Pkt,
631 }).Tracef("Sent TestResult OMCI message")
632
633 return nil
634}
635
William Kurkian0418bc82019-11-06 12:16:24 -0500636func (o *Onu) handleOmciMessage(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700637
638 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700639 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700640 "SerialNumber": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700641 "omciPacket": msg.omciMsg.Pkt,
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700642 }).Tracef("Received OMCI message")
643
Pragya Arya324337e2020-02-20 14:35:08 +0530644 o.publishOmciEvent(msg)
645
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700646 var omciInd openolt.OmciIndication
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700647 respPkt, err := omcisim.OmciSim(o.PonPortID, o.ID, HexDecode(msg.omciMsg.Pkt))
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700648 if err != nil {
Matteo Scandolo27428702019-10-11 16:21:16 -0700649 onuLogger.WithFields(log.Fields{
650 "IntfId": o.PonPortID,
651 "SerialNumber": o.Sn(),
652 "omciPacket": omciInd.Pkt,
653 "msg": msg,
654 }).Errorf("Error handling OMCI message %v", msg)
655 return
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700656 }
657
658 omciInd.IntfId = o.PonPortID
659 omciInd.OnuId = o.ID
660 omciInd.Pkt = respPkt
661
662 omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
663 if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
Matteo Scandolo27428702019-10-11 16:21:16 -0700664 onuLogger.WithFields(log.Fields{
665 "IntfId": o.PonPortID,
666 "SerialNumber": o.Sn(),
667 "omciPacket": omciInd.Pkt,
668 "msg": msg,
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700669 }).Errorf("send omcisim indication failed: %v", err)
Matteo Scandolo27428702019-10-11 16:21:16 -0700670 return
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700671 }
672 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700673 "IntfId": o.PonPortID,
Matteo Scandolo27428702019-10-11 16:21:16 -0700674 "SerialNumber": o.Sn(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700675 "omciPacket": omciInd.Pkt,
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700676 }).Tracef("Sent OMCI message")
Scott Bakerb90c4312020-03-12 21:33:25 -0700677
678 // Test message is special, it requires sending two packets:
679 // first packet: TestResponse, says whether test was started successully, handled by omci-sim
680 // second packet, TestResult, reports the result of running the self-test
681 // TestResult can come some time after a TestResponse
682 // TODO: Implement some delay between the TestResponse and the TestResult
683 isTest, err := omcilib.IsTestRequest(HexDecode(msg.omciMsg.Pkt))
684 if (err == nil) && (isTest) {
685 o.sendTestResult(msg, stream)
686 }
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700687}
688
Matteo Scandolo27428702019-10-11 16:21:16 -0700689func (o *Onu) storePortNumber(portNo uint32) {
Matteo Scandolo813402b2019-10-23 19:24:52 -0700690 // NOTE this needed only as long as we don't support multiple UNIs
Matteo Scandolo27428702019-10-11 16:21:16 -0700691 // we need to add support for multiple UNIs
692 // the action plan is:
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700693 // - refactor the omcisim-sim library to use https://github.com/cboling/omci instead of canned messages
Matteo Scandolo27428702019-10-11 16:21:16 -0700694 // - change the library so that it reports a single UNI and remove this workaroung
695 // - add support for multiple UNIs in BBSim
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700696 if o.PortNo == 0 || portNo < o.PortNo {
Matteo Scandolo813402b2019-10-23 19:24:52 -0700697 onuLogger.WithFields(log.Fields{
698 "IntfId": o.PonPortID,
699 "OnuId": o.ID,
700 "SerialNumber": o.Sn(),
701 "OnuPortNo": o.PortNo,
702 "FlowPortNo": portNo,
703 }).Debug("Storing ONU portNo")
Matteo Scandolo27428702019-10-11 16:21:16 -0700704 o.PortNo = portNo
705 }
706}
707
William Kurkian0418bc82019-11-06 12:16:24 -0500708func (o *Onu) SetID(id uint32) {
Matteo Scandolo583f17d2020-02-13 10:35:17 -0800709 onuLogger.WithFields(log.Fields{
710 "IntfId": o.PonPortID,
711 "OnuId": id,
712 "SerialNumber": o.Sn(),
713 }).Debug("Storing OnuId ")
William Kurkian0418bc82019-11-06 12:16:24 -0500714 o.ID = id
715}
716
Matteo Scandolo813402b2019-10-23 19:24:52 -0700717func (o *Onu) handleFlowUpdate(msg OnuFlowUpdateMessage) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700718 onuLogger.WithFields(log.Fields{
Matteo Scandolod7cc6d32020-02-26 16:51:12 -0800719 "DstPort": msg.Flow.Classifier.DstPort,
720 "EthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
721 "FlowId": msg.Flow.FlowId,
722 "FlowType": msg.Flow.FlowType,
723 "GemportId": msg.Flow.GemportId,
724 "InnerVlan": msg.Flow.Classifier.IVid,
725 "IntfId": msg.Flow.AccessIntfId,
726 "IpProto": msg.Flow.Classifier.IpProto,
727 "OnuId": msg.Flow.OnuId,
728 "OnuSn": o.Sn(),
729 "OuterVlan": msg.Flow.Classifier.OVid,
730 "PortNo": msg.Flow.PortNo,
731 "SrcPort": msg.Flow.Classifier.SrcPort,
732 "UniID": msg.Flow.UniId,
Matteo Scandolo3ac52792020-03-05 14:21:08 -0800733 "ClassifierOPbits": msg.Flow.Classifier.OPbits,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700734 }).Debug("ONU receives Flow")
735
Matteo Scandolo813402b2019-10-23 19:24:52 -0700736 if msg.Flow.UniId != 0 {
737 // as of now BBSim only support a single UNI, so ignore everything that is not targeted to it
738 onuLogger.WithFields(log.Fields{
739 "IntfId": o.PonPortID,
740 "OnuId": o.ID,
741 "SerialNumber": o.Sn(),
742 }).Debug("Ignoring flow as it's not for the first UNI")
743 return
744 }
745
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700746 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
Matteo Scandolo27428702019-10-11 16:21:16 -0700747 // NOTE storing the PortNO, it's needed when sending PacketIndications
Matteo Scandolo813402b2019-10-23 19:24:52 -0700748 o.storePortNumber(uint32(msg.Flow.PortNo))
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800749 o.EapolFlowReceived = true
750 // if authentication is not enabled, do nothing
751 if o.Auth {
752 // NOTE if we receive the EAPOL flows but we don't have GemPorts
753 // wait for it before starting auth
754 if !o.GemPortAdded {
755 // wait for Gem and then start auth
756 go func() {
757 for v := range o.GetGemPortChan() {
758 if v == true {
759 if err := o.InternalState.Event("start_auth"); err != nil {
760 onuLogger.Warnf("Can't go to auth_started: %v", err)
761 }
762 }
763 }
764 onuLogger.Trace("GemPortChannel closed")
765 }()
Matteo Scandoloc1147092019-10-29 09:38:33 -0700766 } else {
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800767 // start the EAPOL state machine
768 if err := o.InternalState.Event("start_auth"); err != nil {
769 onuLogger.Warnf("Can't go to auth_started: %v", err)
770 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700771 }
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800772 } else {
773 onuLogger.WithFields(log.Fields{
774 "IntfId": o.PonPortID,
775 "OnuId": o.ID,
776 "SerialNumber": o.Sn(),
777 }).Warn("Not starting authentication as Auth bit is not set in CLI parameters")
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700778 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700779 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
780 msg.Flow.Classifier.SrcPort == uint32(68) &&
Matteo Scandolo3ac52792020-03-05 14:21:08 -0800781 msg.Flow.Classifier.DstPort == uint32(67) &&
Matteo Scandolod74abba2020-04-16 16:36:44 -0700782 (msg.Flow.Classifier.OPbits == 0 || msg.Flow.Classifier.OPbits == 255) {
Matteo Scandolo99f18462019-10-28 14:14:28 -0700783
Matteo Scandoloc1147092019-10-29 09:38:33 -0700784 if o.Dhcp == true {
Matteo Scandolod74abba2020-04-16 16:36:44 -0700785 if o.DhcpFlowReceived == false {
786 // keep track that we received the DHCP Flows
787 // so that we can transition the state to dhcp_started
788 // this is needed as a check in case someone trigger DHCP from the CLI
789 o.DhcpFlowReceived = true
790
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800791 if !o.GemPortAdded {
792 // wait for Gem and then start DHCP
793 go func() {
794 for v := range o.GetGemPortChan() {
795 if v == true {
796 if err := o.InternalState.Event("start_dhcp"); err != nil {
797 log.Errorf("Can't go to dhcp_started: %v", err)
798 }
799 }
800 }
801 }()
802 } else {
803 // start the DHCP state machine
804 if err := o.InternalState.Event("start_dhcp"); err != nil {
805 log.Errorf("Can't go to dhcp_started: %v", err)
806 }
Matteo Scandolod74abba2020-04-16 16:36:44 -0700807 }
808 } else {
809 onuLogger.WithFields(log.Fields{
810 "IntfId": o.PonPortID,
811 "OnuId": o.ID,
812 "SerialNumber": o.Sn(),
813 "DhcpFlowReceived": o.DhcpFlowReceived,
814 }).Warn("DHCP already started")
Matteo Scandoloc1147092019-10-29 09:38:33 -0700815 }
816 } else {
817 onuLogger.WithFields(log.Fields{
818 "IntfId": o.PonPortID,
819 "OnuId": o.ID,
820 "SerialNumber": o.Sn(),
821 }).Warn("Not starting DHCP as Dhcp bit is not set in CLI parameters")
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700822 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700823 }
824}
825
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700826// HexDecode converts the hex encoding to binary
827func HexDecode(pkt []byte) []byte {
828 p := make([]byte, len(pkt)/2)
829 for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
830 // Go figure this ;)
831 u := (pkt[i] & 15) + (pkt[i]>>6)*9
832 l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
833 p[j] = u<<4 + l
834 }
835 onuLogger.Tracef("Omci decoded: %x.", p)
836 return p
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700837}
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700838
839// BBR methods
840
841func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
842 omciMsg := openolt.OmciMsg{
843 IntfId: intfId,
844 OnuId: onuId,
845 Pkt: pktBytes,
846 }
847
848 if _, err := client.OmciMsgOut(context.Background(), &omciMsg); err != nil {
849 log.WithFields(log.Fields{
850 "IntfId": intfId,
851 "OnuId": onuId,
852 "SerialNumber": common.OnuSnToString(sn),
853 "Pkt": omciMsg.Pkt,
854 }).Fatalf("Failed to send MIB Reset")
855 }
856 log.WithFields(log.Fields{
857 "IntfId": intfId,
858 "OnuId": onuId,
859 "SerialNumber": common.OnuSnToString(sn),
860 "Pkt": omciMsg.Pkt,
861 }).Tracef("Sent OMCI message %s", msgType)
862}
863
864func (onu *Onu) getNextTid(highPriority ...bool) uint16 {
865 var next uint16
866 if len(highPriority) > 0 && highPriority[0] {
867 next = onu.hpTid
868 onu.hpTid += 1
869 if onu.hpTid < 0x8000 {
870 onu.hpTid = 0x8000
871 }
872 } else {
873 next = onu.tid
874 onu.tid += 1
875 if onu.tid >= 0x8000 {
876 onu.tid = 1
877 }
878 }
879 return next
880}
881
882// TODO move this method in responders/omcisim
883func (o *Onu) StartOmci(client openolt.OpenoltClient) {
884 mibReset, _ := omcilib.CreateMibResetRequest(o.getNextTid(false))
885 sendOmciMsg(mibReset, o.PonPortID, o.ID, o.SerialNumber, "mibReset", client)
886}
887
888func (o *Onu) handleOmci(msg OmciIndicationMessage, client openolt.OpenoltClient) {
889 msgType, packet := omcilib.DecodeOmci(msg.OmciInd.Pkt)
890
891 log.WithFields(log.Fields{
892 "IntfId": msg.OmciInd.IntfId,
893 "OnuId": msg.OmciInd.OnuId,
894 "OnuSn": common.OnuSnToString(o.SerialNumber),
895 "Pkt": msg.OmciInd.Pkt,
896 "msgType": msgType,
Anand S Katti09541352020-01-29 15:54:01 +0530897 }).Trace("ONU Receives OMCI Msg")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700898 switch msgType {
899 default:
Matteo Scandolo813402b2019-10-23 19:24:52 -0700900 log.WithFields(log.Fields{
901 "IntfId": msg.OmciInd.IntfId,
902 "OnuId": msg.OmciInd.OnuId,
903 "OnuSn": common.OnuSnToString(o.SerialNumber),
904 "Pkt": msg.OmciInd.Pkt,
905 "msgType": msgType,
906 }).Fatalf("unexpected frame: %v", packet)
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700907 case omci.MibResetResponseType:
908 mibUpload, _ := omcilib.CreateMibUploadRequest(o.getNextTid(false))
909 sendOmciMsg(mibUpload, o.PonPortID, o.ID, o.SerialNumber, "mibUpload", client)
910 case omci.MibUploadResponseType:
911 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
912 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
913 case omci.MibUploadNextResponseType:
914 o.seqNumber++
915
916 if o.seqNumber > 290 {
917 // NOTE we are done with the MIB Upload (290 is the number of messages the omci-sim library will respond to)
918 galEnet, _ := omcilib.CreateGalEnetRequest(o.getNextTid(false))
919 sendOmciMsg(galEnet, o.PonPortID, o.ID, o.SerialNumber, "CreateGalEnetRequest", client)
920 } else {
921 mibUploadNext, _ := omcilib.CreateMibUploadNextRequest(o.getNextTid(false), o.seqNumber)
922 sendOmciMsg(mibUploadNext, o.PonPortID, o.ID, o.SerialNumber, "mibUploadNext", client)
923 }
924 case omci.CreateResponseType:
925 // NOTE Creating a GemPort,
926 // BBsim actually doesn't care about the values, so we can do we want with the parameters
927 // In the same way we can create a GemPort even without setting up UNIs/TConts/...
928 // but we need the GemPort to trigger the state change
929
930 if !o.HasGemPort {
931 // NOTE this sends a CreateRequestType and BBSim replies with a CreateResponseType
932 // thus we send this request only once
933 gemReq, _ := omcilib.CreateGemPortRequest(o.getNextTid(false))
934 sendOmciMsg(gemReq, o.PonPortID, o.ID, o.SerialNumber, "CreateGemPortRequest", client)
935 o.HasGemPort = true
936 } else {
937 if err := o.InternalState.Event("send_eapol_flow"); err != nil {
938 onuLogger.WithFields(log.Fields{
939 "OnuId": o.ID,
940 "IntfId": o.PonPortID,
941 "OnuSn": o.Sn(),
942 }).Errorf("Error while transitioning ONU State %v", err)
943 }
944 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700945 }
946}
947
948func (o *Onu) sendEapolFlow(client openolt.OpenoltClient) {
949
950 classifierProto := openolt.Classifier{
951 EthType: uint32(layers.EthernetTypeEAPOL),
952 OVid: 4091,
953 }
954
955 actionProto := openolt.Action{}
956
957 downstreamFlow := openolt.Flow{
958 AccessIntfId: int32(o.PonPortID),
959 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -0700960 UniId: int32(0), // NOTE do not hardcode this, we need to support multiple UNIs
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700961 FlowId: uint32(o.ID),
962 FlowType: "downstream",
963 AllocId: int32(0),
964 NetworkIntfId: int32(0),
965 GemportId: int32(1), // FIXME use the same value as CreateGemPortRequest PortID, do not hardcode
966 Classifier: &classifierProto,
967 Action: &actionProto,
968 Priority: int32(100),
969 Cookie: uint64(o.ID),
970 PortNo: uint32(o.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
971 }
972
973 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
974 log.WithFields(log.Fields{
975 "IntfId": o.PonPortID,
976 "OnuId": o.ID,
977 "FlowId": downstreamFlow.FlowId,
978 "PortNo": downstreamFlow.PortNo,
979 "SerialNumber": common.OnuSnToString(o.SerialNumber),
Matteo Scandolob0e3e622020-04-23 17:00:29 -0700980 }).Fatalf("Failed to add EAPOL Flow")
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700981 }
982 log.WithFields(log.Fields{
983 "IntfId": o.PonPortID,
984 "OnuId": o.ID,
985 "FlowId": downstreamFlow.FlowId,
986 "PortNo": downstreamFlow.PortNo,
987 "SerialNumber": common.OnuSnToString(o.SerialNumber),
988 }).Info("Sent EAPOL Flow")
989}
990
991func (o *Onu) sendDhcpFlow(client openolt.OpenoltClient) {
992 classifierProto := openolt.Classifier{
993 EthType: uint32(layers.EthernetTypeIPv4),
994 SrcPort: uint32(68),
995 DstPort: uint32(67),
996 }
997
998 actionProto := openolt.Action{}
999
1000 downstreamFlow := openolt.Flow{
1001 AccessIntfId: int32(o.PonPortID),
1002 OnuId: int32(o.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -07001003 UniId: int32(0), // FIXME do not hardcode this
Matteo Scandolo40e067f2019-10-16 16:59:41 -07001004 FlowId: uint32(o.ID),
1005 FlowType: "downstream",
1006 AllocId: int32(0),
1007 NetworkIntfId: int32(0),
1008 GemportId: int32(1), // FIXME use the same value as CreateGemPortRequest PortID, do not hardcode
1009 Classifier: &classifierProto,
1010 Action: &actionProto,
1011 Priority: int32(100),
1012 Cookie: uint64(o.ID),
1013 PortNo: uint32(o.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
1014 }
1015
1016 if _, err := client.FlowAdd(context.Background(), &downstreamFlow); err != nil {
1017 log.WithFields(log.Fields{
1018 "IntfId": o.PonPortID,
1019 "OnuId": o.ID,
1020 "FlowId": downstreamFlow.FlowId,
1021 "PortNo": downstreamFlow.PortNo,
1022 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1023 }).Fatalf("Failed to send DHCP Flow")
1024 }
1025 log.WithFields(log.Fields{
1026 "IntfId": o.PonPortID,
1027 "OnuId": o.ID,
1028 "FlowId": downstreamFlow.FlowId,
1029 "PortNo": downstreamFlow.PortNo,
1030 "SerialNumber": common.OnuSnToString(o.SerialNumber),
1031 }).Info("Sent DHCP Flow")
1032}
Pragya Arya8bdb4532020-03-02 17:08:09 +05301033
1034// DeleteFlow method search and delete flowKey from the onu flows slice
1035func (onu *Onu) DeleteFlow(key FlowKey) {
1036 for pos, flowKey := range onu.Flows {
1037 if flowKey == key {
1038 // delete the flowKey by shifting all flowKeys by one
1039 onu.Flows = append(onu.Flows[:pos], onu.Flows[pos+1:]...)
1040 t := make([]FlowKey, len(onu.Flows))
1041 copy(t, onu.Flows)
1042 onu.Flows = t
1043 break
1044 }
1045 }
1046}