blob: 1464ae5bc967e4c9693f8a2a9fa9cd204939ee30 [file] [log] [blame]
Matteo Scandolo813402b2019-10-23 19:24:52 -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
17package devices
18
19import (
Matteo Scandolo813402b2019-10-23 19:24:52 -070020 "github.com/google/gopacket/layers"
21 "github.com/looplab/fsm"
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070022 "github.com/opencord/voltha-protos/v4/go/openolt"
Matteo Scandolo813402b2019-10-23 19:24:52 -070023 "gotest.tools/assert"
Matteo Scandolo813402b2019-10-23 19:24:52 -070024 "testing"
25)
26
Matteo Scandolo4a036262020-08-17 15:56:13 -070027// test that BBR correctly sends the EAPOL Flow
Matteo Scandolo813402b2019-10-23 19:24:52 -070028func Test_Onu_SendEapolFlow(t *testing.T) {
Matteo Scandolo4a036262020-08-17 15:56:13 -070029 onu := createMockOnu(1, 1)
Matteo Scandolo813402b2019-10-23 19:24:52 -070030
31 client := &mockClient{
32 FlowAddSpy: FlowAddSpy{
33 Calls: make(map[int]*openolt.Flow),
34 },
35 fail: false,
36 }
37
38 onu.sendEapolFlow(client)
39 assert.Equal(t, client.FlowAddSpy.CallCount, 1)
40
41 assert.Equal(t, client.FlowAddSpy.Calls[1].AccessIntfId, int32(onu.PonPortID))
42 assert.Equal(t, client.FlowAddSpy.Calls[1].OnuId, int32(onu.ID))
43 assert.Equal(t, client.FlowAddSpy.Calls[1].UniId, int32(0))
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070044 assert.Equal(t, client.FlowAddSpy.Calls[1].FlowId, uint64(onu.ID))
Matteo Scandolo813402b2019-10-23 19:24:52 -070045 assert.Equal(t, client.FlowAddSpy.Calls[1].FlowType, "downstream")
46 assert.Equal(t, client.FlowAddSpy.Calls[1].PortNo, onu.ID)
47}
48
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070049// checks that the FlowId is added to the list
50func Test_HandleFlowAddFlowId(t *testing.T) {
Matteo Scandolo4a036262020-08-17 15:56:13 -070051 onu := createMockOnu(1, 1)
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070052
53 flow := openolt.Flow{
Shrey Baid688b4242020-07-10 20:40:10 +053054 FlowId: 64,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070055 Classifier: &openolt.Classifier{},
56 }
57 msg := OnuFlowUpdateMessage{
58 OnuID: onu.ID,
59 PonPortID: onu.PonPortID,
60 Flow: &flow,
61 }
62 onu.handleFlowAdd(msg)
63 assert.Equal(t, len(onu.FlowIds), 1)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070064 assert.Equal(t, onu.FlowIds[0], uint64(64))
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070065}
66
Matteo Scandolo4a036262020-08-17 15:56:13 -070067// checks that we only remove the correct flow
68func Test_HandleFlowRemoveFlowId(t *testing.T) {
69 onu := createMockOnu(1, 1)
70
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070071 onu.FlowIds = []uint64{1, 2, 34, 64, 92}
Matteo Scandolo4a036262020-08-17 15:56:13 -070072
73 flow := openolt.Flow{
74 FlowId: 64,
75 Classifier: &openolt.Classifier{},
76 }
77 msg := OnuFlowUpdateMessage{
78 OnuID: onu.ID,
79 PonPortID: onu.PonPortID,
80 Flow: &flow,
81 }
82 onu.handleFlowRemove(msg)
83 assert.Equal(t, len(onu.FlowIds), 4)
Matteo Scandolo4f4ac792020-10-01 16:33:21 -070084 assert.Equal(t, onu.FlowIds[0], uint64(1))
85 assert.Equal(t, onu.FlowIds[1], uint64(2))
86 assert.Equal(t, onu.FlowIds[2], uint64(34))
87 assert.Equal(t, onu.FlowIds[3], uint64(92))
Matteo Scandolo4a036262020-08-17 15:56:13 -070088}
89
90// checks that when the last flow is removed we reset the stored flags in the ONU
91func Test_HandleFlowRemoveFlowId_LastFlow(t *testing.T) {
92 onu := createMockOnu(1, 1)
93
94 onu.InternalState = fsm.NewFSM(
95 "enabled",
96 fsm.Events{
97 {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
98 },
99 fsm.Callbacks{},
100 )
101
102 onu.GemPortAdded = true
103
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700104 onu.FlowIds = []uint64{64}
Matteo Scandolo4a036262020-08-17 15:56:13 -0700105
106 flow := openolt.Flow{
107 FlowId: 64,
108 Classifier: &openolt.Classifier{},
109 }
110 msg := OnuFlowUpdateMessage{
111 OnuID: onu.ID,
112 PonPortID: onu.PonPortID,
113 Flow: &flow,
114 }
115 onu.handleFlowRemove(msg)
116 assert.Equal(t, len(onu.FlowIds), 0)
117 assert.Equal(t, onu.GemPortAdded, false)
118}
119
120func TestOnu_HhandleEAPOLStart(t *testing.T) {
121 onu := createMockOnu(1, 1)
122 hsia := mockService{Name: "hsia"}
123 voip := mockService{Name: "voip"}
124
125 onu.Services = []ServiceIf{&hsia, &voip}
126
127 stream := mockStream{
128 Calls: make(map[int]*openolt.Indication),
129 }
130
131 onu.PonPort.Olt.OpenoltStream = &stream
132
133 flow := openolt.Flow{
134 AccessIntfId: int32(onu.PonPortID),
135 OnuId: int32(onu.ID),
136 UniId: int32(0),
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700137 FlowId: uint64(onu.ID),
Matteo Scandolo4a036262020-08-17 15:56:13 -0700138 FlowType: "downstream",
139 AllocId: int32(0),
140 NetworkIntfId: int32(0),
141 Classifier: &openolt.Classifier{
142 EthType: uint32(layers.EthernetTypeEAPOL),
143 OVid: 4091,
144 },
145 Action: &openolt.Action{},
146 Priority: int32(100),
147 PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
148 }
149
150 msg := OnuFlowUpdateMessage{
151 PonPortID: 1,
152 OnuID: 1,
153 Flow: &flow,
154 }
155
156 onu.handleFlowAdd(msg)
157
158 // check that we call HandleAuth on all the services
159 assert.Equal(t, hsia.HandleAuthCallCount, 1)
160 assert.Equal(t, voip.HandleAuthCallCount, 1)
161}
162
163// TODO all the following tests needs to be moved in the Service model
164
Matteo Scandolo813402b2019-10-23 19:24:52 -0700165// validates that when an ONU receives an EAPOL flow for UNI 0
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800166// and the GemPort has already been configured
Matteo Scandolo813402b2019-10-23 19:24:52 -0700167// it transition to auth_started state
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700168func Test_HandleFlowAddEapolWithGem(t *testing.T) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700169 t.Skip("Needs to be moved in the Service struct")
170 onu := createMockOnu(1, 1)
Matteo Scandolo813402b2019-10-23 19:24:52 -0700171
172 onu.InternalState = fsm.NewFSM(
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800173 "enabled",
Matteo Scandolo813402b2019-10-23 19:24:52 -0700174 fsm.Events{
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800175 {Name: "start_auth", Src: []string{"enabled"}, Dst: "auth_started"},
Matteo Scandolo813402b2019-10-23 19:24:52 -0700176 },
177 fsm.Callbacks{},
178 )
179
180 flow := openolt.Flow{
181 AccessIntfId: int32(onu.PonPortID),
182 OnuId: int32(onu.ID),
183 UniId: int32(0),
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700184 FlowId: uint64(onu.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -0700185 FlowType: "downstream",
186 AllocId: int32(0),
187 NetworkIntfId: int32(0),
188 Classifier: &openolt.Classifier{
189 EthType: uint32(layers.EthernetTypeEAPOL),
190 OVid: 4091,
191 },
192 Action: &openolt.Action{},
193 Priority: int32(100),
194 PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
195 }
196
197 msg := OnuFlowUpdateMessage{
198 PonPortID: 1,
199 OnuID: 1,
200 Flow: &flow,
201 }
202
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700203 onu.handleFlowAdd(msg)
Matteo Scandolo813402b2019-10-23 19:24:52 -0700204 assert.Equal(t, onu.InternalState.Current(), "auth_started")
205}
206
207// validates that when an ONU receives an EAPOL flow for UNI that is not 0
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800208// no action is taken (this is independent of GemPort status
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700209func Test_HandleFlowAddEapolWrongUNI(t *testing.T) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700210 t.Skip("Needs to be moved in the Service struct")
211 onu := createMockOnu(1, 1)
Matteo Scandolo813402b2019-10-23 19:24:52 -0700212
213 onu.InternalState = fsm.NewFSM(
214 "enabled",
215 fsm.Events{
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800216 {Name: "start_auth", Src: []string{"enabled"}, Dst: "auth_started"},
Matteo Scandolo813402b2019-10-23 19:24:52 -0700217 },
218 fsm.Callbacks{},
219 )
220
221 flow := openolt.Flow{
222 AccessIntfId: int32(onu.PonPortID),
223 OnuId: int32(onu.ID),
224 UniId: int32(1),
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700225 FlowId: uint64(onu.ID),
Matteo Scandolo813402b2019-10-23 19:24:52 -0700226 FlowType: "downstream",
227 AllocId: int32(0),
228 NetworkIntfId: int32(0),
229 Classifier: &openolt.Classifier{
230 EthType: uint32(layers.EthernetTypeEAPOL),
231 OVid: 4091,
232 },
233 Action: &openolt.Action{},
234 Priority: int32(100),
235 PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
236 }
237
238 msg := OnuFlowUpdateMessage{
239 PonPortID: 1,
240 OnuID: 1,
241 Flow: &flow,
242 }
243
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700244 onu.handleFlowAdd(msg)
Matteo Scandolo813402b2019-10-23 19:24:52 -0700245 assert.Equal(t, onu.InternalState.Current(), "enabled")
246}
247
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800248// validates that when an ONU receives a DHCP flow for UNI 0 and pbit 0
249// and the GemPort has already been configured
250// it transition to dhcp_started state
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700251func Test_HandleFlowAddDhcp(t *testing.T) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700252 t.Skip("Needs to be moved in the Service struct")
253 onu := createMockOnu(1, 1)
Matteo Scandoloc1147092019-10-29 09:38:33 -0700254
255 onu.InternalState = fsm.NewFSM(
256 "eap_response_success_received",
257 fsm.Events{
258 {Name: "start_dhcp", Src: []string{"eap_response_success_received"}, Dst: "dhcp_started"},
259 },
260 fsm.Callbacks{},
261 )
262
263 flow := openolt.Flow{
264 AccessIntfId: int32(onu.PonPortID),
265 OnuId: int32(onu.ID),
266 UniId: int32(0),
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700267 FlowId: uint64(onu.ID),
Matteo Scandoloc1147092019-10-29 09:38:33 -0700268 FlowType: "downstream",
269 AllocId: int32(0),
270 NetworkIntfId: int32(0),
271 Classifier: &openolt.Classifier{
272 EthType: uint32(layers.EthernetTypeIPv4),
273 SrcPort: uint32(68),
274 DstPort: uint32(67),
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800275 OPbits: 0,
Matteo Scandoloc1147092019-10-29 09:38:33 -0700276 },
277 Action: &openolt.Action{},
278 Priority: int32(100),
279 PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
280 }
281
282 msg := OnuFlowUpdateMessage{
283 PonPortID: 1,
284 OnuID: 1,
285 Flow: &flow,
286 }
287
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700288 onu.handleFlowAdd(msg)
Matteo Scandoloc1147092019-10-29 09:38:33 -0700289 assert.Equal(t, onu.InternalState.Current(), "dhcp_started")
Matteo Scandoloc1147092019-10-29 09:38:33 -0700290}
291
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800292// validates that when an ONU receives a DHCP flow for UNI 0 and pbit 255
293// and the GemPort has already been configured
294// it transition to dhcp_started state
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700295func Test_HandleFlowAddDhcpPBit255(t *testing.T) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700296 t.Skip("Needs to be moved in the Service struct")
297 onu := createMockOnu(1, 1)
Matteo Scandolod74abba2020-04-16 16:36:44 -0700298
299 onu.InternalState = fsm.NewFSM(
300 "eap_response_success_received",
301 fsm.Events{
302 {Name: "start_dhcp", Src: []string{"eap_response_success_received"}, Dst: "dhcp_started"},
303 },
304 fsm.Callbacks{},
305 )
306
307 flow := openolt.Flow{
308 AccessIntfId: int32(onu.PonPortID),
309 OnuId: int32(onu.ID),
310 UniId: int32(0),
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700311 FlowId: uint64(onu.ID),
Matteo Scandolod74abba2020-04-16 16:36:44 -0700312 FlowType: "downstream",
313 AllocId: int32(0),
314 NetworkIntfId: int32(0),
315 Classifier: &openolt.Classifier{
316 EthType: uint32(layers.EthernetTypeIPv4),
317 SrcPort: uint32(68),
318 DstPort: uint32(67),
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800319 OPbits: 255,
Matteo Scandolod74abba2020-04-16 16:36:44 -0700320 },
321 Action: &openolt.Action{},
322 Priority: int32(100),
323 PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
324 }
325
326 msg := OnuFlowUpdateMessage{
327 PonPortID: 1,
328 OnuID: 1,
329 Flow: &flow,
330 }
331
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700332 onu.handleFlowAdd(msg)
Matteo Scandolod74abba2020-04-16 16:36:44 -0700333 assert.Equal(t, onu.InternalState.Current(), "dhcp_started")
Matteo Scandolod74abba2020-04-16 16:36:44 -0700334}
335
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800336// validates that when an ONU receives a DHCP flow for UNI 0 and pbit not 0 or 255
337// and the GemPort has already been configured
338// it ignores the message
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700339func Test_HandleFlowAddDhcpIgnoreByPbit(t *testing.T) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700340 t.Skip("Needs to be moved in the Service struct")
341 onu := createMockOnu(1, 1)
Matteo Scandolod74abba2020-04-16 16:36:44 -0700342
343 onu.InternalState = fsm.NewFSM(
344 "eap_response_success_received",
345 fsm.Events{
346 {Name: "start_dhcp", Src: []string{"eap_response_success_received"}, Dst: "dhcp_started"},
347 },
348 fsm.Callbacks{},
349 )
350
351 flow := openolt.Flow{
352 AccessIntfId: int32(onu.PonPortID),
353 OnuId: int32(onu.ID),
354 UniId: int32(0),
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700355 FlowId: uint64(onu.ID),
Matteo Scandolod74abba2020-04-16 16:36:44 -0700356 FlowType: "downstream",
357 AllocId: int32(0),
358 NetworkIntfId: int32(0),
359 Classifier: &openolt.Classifier{
360 EthType: uint32(layers.EthernetTypeIPv4),
361 SrcPort: uint32(68),
362 DstPort: uint32(67),
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800363 OPbits: 1,
Matteo Scandolod74abba2020-04-16 16:36:44 -0700364 },
365 Action: &openolt.Action{},
366 Priority: int32(100),
367 PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
368 }
369
370 msg := OnuFlowUpdateMessage{
371 PonPortID: 1,
372 OnuID: 1,
373 Flow: &flow,
374 }
375
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700376 onu.handleFlowAdd(msg)
Matteo Scandolod74abba2020-04-16 16:36:44 -0700377 assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
Matteo Scandolod74abba2020-04-16 16:36:44 -0700378}
379
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800380// validates that when an ONU receives a DHCP flow for UNI 0
381// but the noDchp bit is set no action is taken
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700382func Test_HandleFlowAddDhcpNoDhcp(t *testing.T) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700383 t.Skip("Needs to be moved in the Service struct")
384 onu := createMockOnu(1, 1)
Matteo Scandoloc1147092019-10-29 09:38:33 -0700385
386 onu.InternalState = fsm.NewFSM(
387 "eap_response_success_received",
388 fsm.Events{
389 {Name: "start_dhcp", Src: []string{"eap_response_success_received"}, Dst: "dhcp_started"},
390 },
391 fsm.Callbacks{},
392 )
393
394 flow := openolt.Flow{
395 AccessIntfId: int32(onu.PonPortID),
396 OnuId: int32(onu.ID),
397 UniId: int32(0),
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700398 FlowId: uint64(onu.ID),
Matteo Scandoloc1147092019-10-29 09:38:33 -0700399 FlowType: "downstream",
400 AllocId: int32(0),
401 NetworkIntfId: int32(0),
402 Classifier: &openolt.Classifier{
403 EthType: uint32(layers.EthernetTypeIPv4),
404 SrcPort: uint32(68),
405 DstPort: uint32(67),
406 },
407 Action: &openolt.Action{},
408 Priority: int32(100),
409 PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
410 }
411
412 msg := OnuFlowUpdateMessage{
413 PonPortID: 1,
414 OnuID: 1,
415 Flow: &flow,
416 }
417
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700418 onu.handleFlowAdd(msg)
Matteo Scandoloc1147092019-10-29 09:38:33 -0700419 assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
Matteo Scandoloc1147092019-10-29 09:38:33 -0700420}
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800421
422// validates that when an ONU receives a DHCP flow for UNI 0 and pbit not 0 or 255
423// and the GemPort has not already been configured
424// it transition to dhcp_started state
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700425func Test_HandleFlowAddDhcpWithoutGem(t *testing.T) {
Matteo Scandolo4a036262020-08-17 15:56:13 -0700426 t.Skip("Needs to be moved in the Service struct")
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700427 // NOTE that this feature is required as there is no guarantee that the gemport is the same
428 // one we received with the EAPOL flow
Matteo Scandolo4a036262020-08-17 15:56:13 -0700429 onu := createMockOnu(1, 1)
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800430
431 onu.GemPortAdded = false
432
433 onu.InternalState = fsm.NewFSM(
434 "enabled",
435 fsm.Events{
436 {Name: "start_dhcp", Src: []string{"enabled"}, Dst: "dhcp_started"},
437 },
438 fsm.Callbacks{},
439 )
440
441 flow := openolt.Flow{
442 AccessIntfId: int32(onu.PonPortID),
443 OnuId: int32(onu.ID),
444 UniId: int32(0),
Matteo Scandolo4f4ac792020-10-01 16:33:21 -0700445 FlowId: uint64(onu.ID),
Matteo Scandolo5ff80082019-12-20 13:20:57 -0800446 FlowType: "downstream",
447 AllocId: int32(0),
448 NetworkIntfId: int32(0),
449 Classifier: &openolt.Classifier{
450 EthType: uint32(layers.EthernetTypeIPv4),
451 SrcPort: uint32(68),
452 DstPort: uint32(67),
453 OPbits: 0,
454 },
455 Action: &openolt.Action{},
456 Priority: int32(100),
457 PortNo: uint32(onu.ID), // NOTE we are using this to map an incoming packetIndication to an ONU
458 }
459
460 msg := OnuFlowUpdateMessage{
461 PonPortID: 1,
462 OnuID: 1,
463 Flow: &flow,
464 }
465
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -0700466 onu.handleFlowAdd(msg)
Hardik Windlass7b3405b2020-07-08 15:10:05 +0530467}