blob: dbd9ab7a21f44b2e57f82342da3b3196ca3c698c [file] [log] [blame]
khenaidoo0458db62019-06-20 08:50:36 -04001// +build integration
2
3/*
4 * Copyright 2018-present Open Networking Foundation
5
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9
10 * http://www.apache.org/licenses/LICENSE-2.0
11
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18package core
19
20import (
21 "context"
22 "fmt"
23 "github.com/google/uuid"
khenaidoo0458db62019-06-20 08:50:36 -040024 fu "github.com/opencord/voltha-go/rw_core/utils"
25 tu "github.com/opencord/voltha-go/tests/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080026 "github.com/opencord/voltha-lib-go/v3/pkg/log"
27 "github.com/opencord/voltha-protos/v3/go/common"
28 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
29 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoo0458db62019-06-20 08:50:36 -040030 "github.com/stretchr/testify/assert"
31 "google.golang.org/grpc/metadata"
32 "math"
33 "os"
Manikkaraj kb1a10922019-07-29 12:10:34 -040034 "reflect"
35 "sync"
khenaidoo0458db62019-06-20 08:50:36 -040036 "testing"
37 "time"
38)
39
40var stub voltha.VolthaServiceClient
41var volthaSerialNumberKey string
Manikkaraj kb1a10922019-07-29 12:10:34 -040042var mutex sync.Mutex
khenaidoo0458db62019-06-20 08:50:36 -040043
44/*
45 This local "integration" test uses one RW-Core, one simulated_olt and one simulated_onu adapter to test flows
46(add/delete), in a development environment. It uses docker-compose to set up the local environment. However, it can
47easily be extended to run in k8s environment.
48
49The compose files used are located under %GOPATH/src/github.com/opencord/voltha-go/compose. If the GOPATH is not set
50then you can specify the location of the compose files by using COMPOSE_PATH to set the compose files location.
51
52To run this test: DOCKER_HOST_IP=<local IP> go test -v
53
54NOTE: Since this is an integration test that involves several containers and features (device creation, device
55activation, validation of parent and discovered devices, validation of logical device as well as add/delete flows)
56then a failure can occur anywhere not just when testing flows.
57
58*/
59
60var allDevices map[string]*voltha.Device
61var allLogicalDevices map[string]*voltha.LogicalDevice
62
63var composePath string
64
65const (
Manikkaraj kb1a10922019-07-29 12:10:34 -040066 GrpcPort = 50057
67 NumOfOLTs = 1
68 NumOfONUsPerOLT = 4 // This should coincide with the number of onus per olt in adapters-simulated.yml file
69 MeterIDStart = 1
70 MeterIDStop = 1000
khenaidoo0458db62019-06-20 08:50:36 -040071)
72
73func setup() {
74 var err error
75
76 if _, err = log.AddPackage(log.JSON, log.WarnLevel, log.Fields{"instanceId": "testing"}); err != nil {
77 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
78 }
79 log.UpdateAllLoggers(log.Fields{"instanceId": "testing"})
80 log.SetAllLogLevel(log.ErrorLevel)
81
82 volthaSerialNumberKey = "voltha_serial_number"
83 allDevices = make(map[string]*voltha.Device)
84 allLogicalDevices = make(map[string]*voltha.LogicalDevice)
85
86 grpcHostIP := os.Getenv("DOCKER_HOST_IP")
87 goPath := os.Getenv("GOPATH")
88 if goPath != "" {
89 composePath = fmt.Sprintf("%s/src/github.com/opencord/voltha-go/compose", goPath)
90 } else {
91 composePath = os.Getenv("COMPOSE_PATH")
92 }
93
94 fmt.Println("Using compose path:", composePath)
95
96 //Start the simulated environment
97 if err = tu.StartSimulatedEnv(composePath); err != nil {
98 fmt.Println("Failure starting simulated environment:", err)
99 os.Exit(10)
100 }
101
Manikkaraj kb1a10922019-07-29 12:10:34 -0400102 stub, err = tu.SetupGrpcConnectionToCore(grpcHostIP, GrpcPort)
khenaidoo0458db62019-06-20 08:50:36 -0400103 if err != nil {
104 fmt.Println("Failure connecting to Voltha Core:", err)
105 os.Exit(11)
106 }
107
108 // Wait for the simulated devices to be registered in the Voltha Core
109 adapters := []string{"simulated_olt", "simulated_onu"}
110 if _, err = tu.WaitForAdapterRegistration(stub, adapters, 20); err != nil {
111 fmt.Println("Failure retrieving adapters:", err)
112 os.Exit(12)
113 }
114}
115
116func shutdown() {
117 err := tu.StopSimulatedEnv(composePath)
118 if err != nil {
119 fmt.Println("Failure stop simulated environment:", err)
120 }
121}
122
123func refreshLocalDeviceCache(stub voltha.VolthaServiceClient) error {
124 retrievedDevices, err := tu.ListDevices(stub)
125 if err != nil {
126 return err
127 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400128 mutex.Lock()
khenaidoo0458db62019-06-20 08:50:36 -0400129 for _, d := range retrievedDevices.Items {
130 allDevices[d.Id] = d
131 }
khenaidoo0458db62019-06-20 08:50:36 -0400132 retrievedLogicalDevices, err := tu.ListLogicalDevices(stub)
133 if err != nil {
134 return err
135 }
136
137 for _, ld := range retrievedLogicalDevices.Items {
138 allLogicalDevices[ld.Id] = ld
139 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400140 mutex.Unlock()
khenaidoo0458db62019-06-20 08:50:36 -0400141 return nil
142}
143
144func makeSimpleFlowMod(fa *fu.FlowArgs) *ofp.OfpFlowMod {
145 matchFields := make([]*ofp.OfpOxmField, 0)
146 for _, val := range fa.MatchFields {
147 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
148 }
149 return fu.MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV)
150}
151
Manikkaraj kb1a10922019-07-29 12:10:34 -0400152func addEAPOLFlow(stub voltha.VolthaServiceClient, ld *voltha.LogicalDevice, port *voltha.LogicalPort, meterID uint64,
153 ch chan interface{}) {
khenaidoo0458db62019-06-20 08:50:36 -0400154 var fa *fu.FlowArgs
155 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400156 KV: fu.OfpFlowModArgs{"priority": 2000, "meter_id": meterID},
khenaidoo0458db62019-06-20 08:50:36 -0400157 MatchFields: []*ofp.OfpOxmOfbField{
158 fu.InPort(port.OfpPort.PortNo),
159 fu.EthType(0x888e),
160 },
161 Actions: []*ofp.OfpAction{
162 fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
163 },
164 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400165 // Don't add meterID 0
166 if meterID == 0 {
167 delete(fa.KV, "meter_id")
168 }
169
khenaidoo0458db62019-06-20 08:50:36 -0400170 matchFields := make([]*ofp.OfpOxmField, 0)
171 for _, val := range fa.MatchFields {
172 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
173 }
174 f := ofp.FlowTableUpdate{FlowMod: makeSimpleFlowMod(fa), Id: ld.Id}
175
176 ui := uuid.New()
177 ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(volthaSerialNumberKey, ui.String()))
178 if response, err := stub.UpdateLogicalDeviceFlowTable(ctx, &f); err != nil {
179 ch <- err
180 } else {
181 ch <- response
182 }
183}
184
185func getNumUniPort(ld *voltha.LogicalDevice, lPortNos ...uint32) int {
186 num := 0
187 if len(lPortNos) > 0 {
188 for _, pNo := range lPortNos {
189 for _, lPort := range ld.Ports {
190 if !lPort.RootPort && lPort.OfpPort.PortNo == pNo {
191 num += 1
192 }
193 }
194 }
195 } else {
196 for _, port := range ld.Ports {
197 if !port.RootPort {
198 num += 1
199 }
200 }
201 }
202 return num
203}
204
205func filterOutPort(lPort *voltha.LogicalPort, lPortNos ...uint32) bool {
206 if len(lPortNos) == 0 {
207 return false
208 }
209 for _, pNo := range lPortNos {
210 if lPort.OfpPort.PortNo == pNo {
211 return false
212 }
213 }
214 return true
215}
216
Manikkaraj kb1a10922019-07-29 12:10:34 -0400217func verifyEAPOLFlows(t *testing.T, ld *voltha.LogicalDevice, meterID uint64, lPortNos ...uint32) {
khenaidoo0458db62019-06-20 08:50:36 -0400218 // First get the flows from the logical device
Manikkaraj kb1a10922019-07-29 12:10:34 -0400219 fmt.Println("Info: verifying EAPOL flows")
khenaidoo0458db62019-06-20 08:50:36 -0400220 lFlows := ld.Flows
221 assert.Equal(t, getNumUniPort(ld, lPortNos...), len(lFlows.Items))
222
223 onuDeviceId := ""
224
225 // Verify that the flows in the logical device is what was pushed
226 for _, lPort := range ld.Ports {
227 if lPort.RootPort {
228 continue
229 }
230 if filterOutPort(lPort, lPortNos...) {
231 continue
232 }
233 onuDeviceId = lPort.DeviceId
234 var fa *fu.FlowArgs
235 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400236 KV: fu.OfpFlowModArgs{"priority": 2000, "meter_id": meterID},
khenaidoo0458db62019-06-20 08:50:36 -0400237 MatchFields: []*ofp.OfpOxmOfbField{
238 fu.InPort(lPort.OfpPort.PortNo),
239 fu.EthType(0x888e),
240 },
241 Actions: []*ofp.OfpAction{
242 fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
243 },
244 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400245 if meterID == 0 {
246 delete(fa.KV, "meter_id")
247 }
khenaidoo0458db62019-06-20 08:50:36 -0400248 expectedLdFlow := fu.MkFlowStat(fa)
249 assert.Equal(t, true, tu.IsFlowPresent(expectedLdFlow, lFlows.Items))
250 }
251
252 // Verify the OLT flows
253 retrievedOltFlows := allDevices[ld.RootDeviceId].Flows.Items
Manikkaraj kb1a10922019-07-29 12:10:34 -0400254 assert.Equal(t, NumOfOLTs*getNumUniPort(ld, lPortNos...)*1, len(retrievedOltFlows))
khenaidoo0458db62019-06-20 08:50:36 -0400255 for _, lPort := range ld.Ports {
256 if lPort.RootPort {
257 continue
258 }
259 if filterOutPort(lPort, lPortNos...) {
260 continue
261 }
262
263 fa := &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400264 KV: fu.OfpFlowModArgs{"priority": 2000, "meter_id": meterID},
khenaidoo0458db62019-06-20 08:50:36 -0400265 MatchFields: []*ofp.OfpOxmOfbField{
266 fu.InPort(1),
khenaidoo0458db62019-06-20 08:50:36 -0400267 fu.TunnelId(uint64(lPort.OfpPort.PortNo)),
268 fu.EthType(0x888e),
269 },
270 Actions: []*ofp.OfpAction{
271 fu.PushVlan(0x8100),
272 fu.SetField(fu.VlanVid(uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000)),
273 fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
274 },
275 }
276 expectedOltFlow := fu.MkFlowStat(fa)
277 assert.Equal(t, true, tu.IsFlowPresent(expectedOltFlow, retrievedOltFlows))
khenaidoo0458db62019-06-20 08:50:36 -0400278 }
279 // Verify the ONU flows
280 retrievedOnuFlows := allDevices[onuDeviceId].Flows.Items
281 assert.Equal(t, 0, len(retrievedOnuFlows))
282}
283
284func verifyNOFlows(t *testing.T, ld *voltha.LogicalDevice, lPortNos ...uint32) {
285 if len(lPortNos) == 0 {
286 assert.Equal(t, 0, len(ld.Flows.Items))
287 for _, d := range allDevices {
288 if d.ParentId == ld.Id {
289 assert.Equal(t, 0, len(d.Flows.Items))
290 }
291 }
292 return
293 }
294 for _, p := range lPortNos {
295 // Check absence of flows in logical device for that port
296 for _, f := range ld.Flows.Items {
297 assert.NotEqual(t, p, fu.GetInPort(f))
298 }
299 // Check absence of flows in the parent device for that port
300 for _, d := range allDevices {
301 if d.ParentId == ld.Id {
302 for _, f := range d.Flows.Items {
303 assert.NotEqual(t, p, fu.GetTunnelId(f))
304 }
305 }
306 }
307 // TODO: check flows in child device. Not required for the use cases being tested
308 }
309
310}
311
Manikkaraj kb1a10922019-07-29 12:10:34 -0400312func installEapolFlows(stub voltha.VolthaServiceClient, lDevice *voltha.LogicalDevice, meterID uint64, lPortNos ...uint32) error {
khenaidoo0458db62019-06-20 08:50:36 -0400313 requestNum := 0
314 combineCh := make(chan interface{})
315 if len(lPortNos) > 0 {
316 fmt.Println("Installing EAPOL flows on ports:", lPortNos)
317 for _, p := range lPortNos {
318 for _, lport := range lDevice.Ports {
319 if !lport.RootPort && lport.OfpPort.PortNo == p {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400320 go addEAPOLFlow(stub, lDevice, lport, meterID, combineCh)
khenaidoo0458db62019-06-20 08:50:36 -0400321 requestNum += 1
322 }
323 }
324 }
325 } else {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400326 fmt.Println("Installing EAPOL flows on logical device", lDevice.Id)
khenaidoo0458db62019-06-20 08:50:36 -0400327 for _, lport := range lDevice.Ports {
328 if !lport.RootPort {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400329 go addEAPOLFlow(stub, lDevice, lport, meterID, combineCh)
khenaidoo0458db62019-06-20 08:50:36 -0400330 requestNum += 1
331 }
332 }
khenaidoo0458db62019-06-20 08:50:36 -0400333 }
334 receivedResponse := 0
335 var err error
336 for {
337 select {
338 case res, ok := <-combineCh:
339 receivedResponse += 1
340 if !ok {
341 } else if er, ok := res.(error); ok {
342 err = er
343 }
344 }
345 if receivedResponse == requestNum {
346 break
347 }
348 }
349 return err
350}
351
352func deleteAllFlows(stub voltha.VolthaServiceClient, lDevice *voltha.LogicalDevice) error {
353 fmt.Println("Deleting all flows for logical device:", lDevice.Id)
354 ui := uuid.New()
355 ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(volthaSerialNumberKey, ui.String()))
356 ch := make(chan interface{})
357 defer close(ch)
358 fa := &fu.FlowArgs{
359 KV: fu.OfpFlowModArgs{"table_id": uint64(ofp.OfpTable_OFPTT_ALL),
360 "cookie_mask": 0,
361 "out_port": uint64(ofp.OfpPortNo_OFPP_ANY),
362 "out_group": uint64(ofp.OfpGroup_OFPG_ANY),
363 },
364 }
365 cmd := ofp.OfpFlowModCommand_OFPFC_DELETE
366 fa.Command = &cmd
367 flowMod := fu.MkSimpleFlowMod(fu.ToOfpOxmField(fa.MatchFields), fa.Actions, fa.Command, fa.KV)
368 f := ofp.FlowTableUpdate{FlowMod: flowMod, Id: lDevice.Id}
369 _, err := stub.UpdateLogicalDeviceFlowTable(ctx, &f)
370 return err
371}
372
Manikkaraj kb1a10922019-07-29 12:10:34 -0400373func deleteEapolFlow(stub voltha.VolthaServiceClient, lDevice *voltha.LogicalDevice, meterID uint64, lPortNo uint32) error {
khenaidoo0458db62019-06-20 08:50:36 -0400374 fmt.Println("Deleting flows from port ", lPortNo, " of logical device ", lDevice.Id)
375 ui := uuid.New()
376 var fa *fu.FlowArgs
377 ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(volthaSerialNumberKey, ui.String()))
378 fa = &fu.FlowArgs{
Manikkaraj kb1a10922019-07-29 12:10:34 -0400379 KV: fu.OfpFlowModArgs{"priority": 2000, "meter_id": meterID},
khenaidoo0458db62019-06-20 08:50:36 -0400380 MatchFields: []*ofp.OfpOxmOfbField{
381 fu.InPort(lPortNo),
382 fu.EthType(0x888e),
383 },
384 Actions: []*ofp.OfpAction{
385 fu.Output(uint32(ofp.OfpPortNo_OFPP_CONTROLLER)),
386 },
387 }
388 matchFields := make([]*ofp.OfpOxmField, 0)
389 for _, val := range fa.MatchFields {
390 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
391 }
392 cmd := ofp.OfpFlowModCommand_OFPFC_DELETE
393 fa.Command = &cmd
394 f := ofp.FlowTableUpdate{FlowMod: makeSimpleFlowMod(fa), Id: lDevice.Id}
395 _, err := stub.UpdateLogicalDeviceFlowTable(ctx, &f)
396 return err
397}
398
Manikkaraj kb1a10922019-07-29 12:10:34 -0400399func runInstallEapolFlows(t *testing.T, stub voltha.VolthaServiceClient, meterID uint64, lPortNos ...uint32) {
khenaidoo0458db62019-06-20 08:50:36 -0400400 err := refreshLocalDeviceCache(stub)
401 assert.Nil(t, err)
402
403 for _, ld := range allLogicalDevices {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400404 err = installEapolFlows(stub, ld, meterID, lPortNos...)
khenaidoo0458db62019-06-20 08:50:36 -0400405 assert.Nil(t, err)
406 }
407
408 err = refreshLocalDeviceCache(stub)
409 assert.Nil(t, err)
khenaidoo0458db62019-06-20 08:50:36 -0400410 for _, ld := range allLogicalDevices {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400411 verifyEAPOLFlows(t, ld, meterID, lPortNos...)
khenaidoo0458db62019-06-20 08:50:36 -0400412 }
413}
414
415func runDeleteAllFlows(t *testing.T, stub voltha.VolthaServiceClient) {
416 fmt.Println("Removing ALL flows ...")
417 err := refreshLocalDeviceCache(stub)
418 assert.Nil(t, err)
419
420 for _, ld := range allLogicalDevices {
421 err = deleteAllFlows(stub, ld)
422 assert.Nil(t, err)
423 }
424
425 err = refreshLocalDeviceCache(stub)
426 assert.Nil(t, err)
427
428 for _, ld := range allLogicalDevices {
429 verifyNOFlows(t, ld)
430 }
431}
432
Manikkaraj kb1a10922019-07-29 12:10:34 -0400433func runDeleteEapolFlows(t *testing.T, stub voltha.VolthaServiceClient, ld *voltha.LogicalDevice, meterID uint64, lPortNos ...uint32) {
khenaidoo0458db62019-06-20 08:50:36 -0400434 err := refreshLocalDeviceCache(stub)
435 assert.Nil(t, err)
436
437 if len(lPortNos) == 0 {
438 err = deleteAllFlows(stub, ld)
439 assert.Nil(t, err)
440 } else {
441 for _, lPortNo := range lPortNos {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400442 err = deleteEapolFlow(stub, ld, meterID, lPortNo)
khenaidoo0458db62019-06-20 08:50:36 -0400443 assert.Nil(t, err)
444 }
445 }
446
447 err = refreshLocalDeviceCache(stub)
448 assert.Nil(t, err)
449
450 for _, lde := range allLogicalDevices {
451 if lde.Id == ld.Id {
452 verifyNOFlows(t, lde, lPortNos...)
453 break
454 }
455 }
456}
457
Manikkaraj kb1a10922019-07-29 12:10:34 -0400458func formulateMeterModUpdateRequest(command ofp.OfpMeterModCommand, meterType ofp.OfpMeterBandType, ldID string, rate,
459 burstSize uint32, meterID uint32) *ofp.MeterModUpdate {
460 meterModUpdateRequest := &ofp.MeterModUpdate{
461 Id: ldID,
462 MeterMod: &ofp.OfpMeterMod{
463 Command: command,
464 Flags: 0,
465 MeterId: meterID,
466 Bands: []*ofp.OfpMeterBandHeader{{
467 Type: meterType,
468 Rate: rate,
469 BurstSize: burstSize,
470 Data: nil,
471 }},
472 },
473 }
474 return meterModUpdateRequest
475}
476
477func formulateMeters(rate, burstsize, meterID uint32, flowCount uint32) *ofp.Meters {
478 // Formulate and return the applied meter band
479 ofpMeterBandHeaderSlice := []*ofp.OfpMeterBandHeader{{
480 Type: ofp.OfpMeterBandType_OFPMBT_EXPERIMENTER,
481 Rate: rate,
482 BurstSize: burstsize,
483 }}
484 BandStats := []*ofp.OfpMeterBandStats{{}}
485 appliedMeters_Meters := []*ofp.OfpMeterEntry{{
486 Config: &ofp.OfpMeterConfig{
487 Flags: 0,
488 MeterId: meterID,
489 Bands: ofpMeterBandHeaderSlice,
490 },
491 Stats: &ofp.OfpMeterStats{
492 MeterId: meterID,
493 BandStats: BandStats,
494 FlowCount: flowCount,
495 },
496 }}
497 appliedMeters := &ofp.Meters{
498 Items: appliedMeters_Meters,
499 }
500 return appliedMeters
501}
502
503func meterAdd(t *testing.T, meterID, rate, burstSize uint32) {
504 var err error
505 for _, logicalDevice := range allLogicalDevices {
506 meterModupdateRequest := formulateMeterModUpdateRequest(ofp.OfpMeterModCommand_OFPMC_ADD,
507 ofp.OfpMeterBandType_OFPMBT_EXPERIMENTER, logicalDevice.Id, rate, burstSize, meterID)
508 _, err = stub.UpdateLogicalDeviceMeterTable(context.Background(), meterModupdateRequest)
509 assert.Nil(t, err)
510 }
511}
512
513func meterMod(t *testing.T, meterID, rate, burstSize uint32) {
514 for _, logicalDevice := range allLogicalDevices {
515 meterModUpdateRequest := formulateMeterModUpdateRequest(ofp.OfpMeterModCommand_OFPMC_MODIFY,
516 ofp.OfpMeterBandType_OFPMBT_EXPERIMENTER, logicalDevice.Id, rate, burstSize, meterID)
517 _, err := stub.UpdateLogicalDeviceMeterTable(context.Background(), meterModUpdateRequest)
518 assert.Nil(t, err)
519 }
520}
521
522//MeterDel deletes a meter with given meter-ID
523func meterDel(t *testing.T, meterID uint32) {
524 for _, logicalDevice := range allLogicalDevices {
525 meterModUpdateRequest := formulateMeterModUpdateRequest(ofp.OfpMeterModCommand_OFPMC_DELETE,
526 ofp.OfpMeterBandType_OFPMBT_EXPERIMENTER, logicalDevice.Id, uint32(1600), uint32(1600), meterID)
527 _, err := stub.UpdateLogicalDeviceMeterTable(context.Background(), meterModUpdateRequest)
528 assert.Nil(t, err)
529 }
530}
531
532// WaitGroup passed to this function must not be nil
533func addMultipleMeterSequentially(t *testing.T, startMeterId, endMeterId, rate, burstSize uint32, wg *sync.WaitGroup) {
534 defer wg.Done()
535 for meterID := startMeterId; meterID <= endMeterId; meterID++ {
536 meterAdd(t, meterID, rate, burstSize)
537 }
538}
539
540func modMultipleMeterSequentially(t *testing.T, startMeterId, endMeterId, rate, burstSize uint32, wg *sync.WaitGroup) {
541 defer wg.Done()
542 for meterID := startMeterId; meterID <= endMeterId; meterID++ {
543 meterMod(t, meterID, rate, burstSize)
544 }
545}
546
547func delMultipleMeterSequential(t *testing.T, startMeterId, endMeterId uint32, wg *sync.WaitGroup) {
548 defer wg.Done()
549 for meterID := startMeterId; meterID <= endMeterId; meterID++ {
550 meterDel(t, meterID)
551 }
552}
553
554func verifyMeter(t *testing.T, meterID, rate, burstSize, flowCount uint32) {
555 expectedMeter := formulateOfpMeterEntry(meterID, flowCount, rate, burstSize)
556 isMeterPresent := false
557 for _, lD := range allLogicalDevices {
558 for _, meter := range lD.Meters.Items {
559 isMeterPresent = reflect.DeepEqual(meter, expectedMeter)
560 if isMeterPresent == true {
561 break
562 }
563 }
564 if isMeterPresent {
565 break
566 }
567 }
568 if !isMeterPresent {
569 fmt.Printf("Error : Expected %+v\n", expectedMeter)
570 }
571 assert.Equal(t, true, isMeterPresent)
572}
573
574func verifyNoMeters(t *testing.T) {
575 err := refreshLocalDeviceCache(stub)
576 assert.Nil(t, err)
577 expectedMeters := &ofp.Meters{}
578 for _, logicalDevice := range allLogicalDevices {
579 result := reflect.DeepEqual(logicalDevice.Meters, expectedMeters)
580 fmt.Println("Meter Present After Delete :--- ", logicalDevice.Meters)
581 assert.Equal(t, true, result)
582 }
583}
584
585func formulateOfpMeterEntry(meterID, flowCount, rate, burstSize uint32) *ofp.OfpMeterEntry {
586 value := &ofp.OfpMeterEntry{
587 Config: &ofp.OfpMeterConfig{
588 MeterId: meterID,
589 Bands: []*ofp.OfpMeterBandHeader{{
590 Type: ofp.OfpMeterBandType_OFPMBT_EXPERIMENTER,
591 Rate: rate,
592 BurstSize: burstSize,
593 }},
594 },
595 Stats: &ofp.OfpMeterStats{
596 MeterId: meterID,
597 FlowCount: flowCount,
598 BandStats: []*ofp.OfpMeterBandStats{{}},
599 },
600 }
601
602 return value
603}
604
605func deleteAllMeters(t *testing.T) {
606 err := refreshLocalDeviceCache(stub)
607 assert.Nil(t, err)
608 for _, lD := range allLogicalDevices {
609 for _, meter := range lD.Meters.Items {
610 meterDel(t, meter.Config.MeterId)
611 }
612 }
613}
614
615func installMultipleFlowsWithMeter(t *testing.T, startMeterId, stopMeterId uint64, wg *sync.WaitGroup) {
616 defer wg.Done()
617 err := refreshLocalDeviceCache(stub)
618 assert.Nil(t, err)
619
620 for meterID := startMeterId; meterID <= stopMeterId; meterID++ {
621 runInstallEapolFlows(t, stub, uint64(meterID), 100, 101)
622 }
623}
624
khenaidoo0458db62019-06-20 08:50:36 -0400625func createAndEnableDevices(t *testing.T) {
626 err := tu.SetAllLogLevel(stub, voltha.Logging{Level: common.LogLevel_WARNING})
627 assert.Nil(t, err)
628
629 err = tu.SetLogLevel(stub, voltha.Logging{Level: common.LogLevel_DEBUG, PackageName: "github.com/opencord/voltha-go/rw_core/core"})
630 assert.Nil(t, err)
631
632 startTime := time.Now()
633
634 //Pre-provision the parent device
635 oltDevice, err := tu.PreProvisionDevice(stub)
636 assert.Nil(t, err)
637
Manikkaraj kb1a10922019-07-29 12:10:34 -0400638 fmt.Println("Creation of ", NumOfOLTs, " OLT devices took:", time.Since(startTime))
khenaidoo0458db62019-06-20 08:50:36 -0400639
640 startTime = time.Now()
641
642 //Enable all parent device - this will enable the child devices as well as validate the child devices
Manikkaraj kb1a10922019-07-29 12:10:34 -0400643 err = tu.EnableDevice(stub, oltDevice, NumOfONUsPerOLT)
khenaidoo0458db62019-06-20 08:50:36 -0400644 assert.Nil(t, err)
645
646 fmt.Println("Enabling of OLT device took:", time.Since(startTime))
647
648 // Wait until the core and adapters sync up after an enabled
Manikkaraj kb1a10922019-07-29 12:10:34 -0400649 time.Sleep(time.Duration(math.Max(10, float64(NumOfOLTs*NumOfONUsPerOLT)/2)) * time.Second)
khenaidoo0458db62019-06-20 08:50:36 -0400650
Manikkaraj kb1a10922019-07-29 12:10:34 -0400651 err = tu.VerifyDevices(stub, NumOfONUsPerOLT)
khenaidoo0458db62019-06-20 08:50:36 -0400652 assert.Nil(t, err)
653
Manikkaraj kb1a10922019-07-29 12:10:34 -0400654 lds, err := tu.VerifyLogicalDevices(stub, oltDevice, NumOfONUsPerOLT)
khenaidoo0458db62019-06-20 08:50:36 -0400655 assert.Nil(t, err)
656 assert.Equal(t, 1, len(lds.Items))
657}
658
659func TestFlowManagement(t *testing.T) {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400660 //1. Test creation and activation of the devices. This will validate the devices as well as the logical device created
khenaidoo0458db62019-06-20 08:50:36 -0400661 createAndEnableDevices(t)
662
663 //2. Test installation of EAPOL flows
Manikkaraj kb1a10922019-07-29 12:10:34 -0400664 runInstallEapolFlows(t, stub, 0)
khenaidoo0458db62019-06-20 08:50:36 -0400665
666 //3. Test deletion of all EAPOL flows
667 runDeleteAllFlows(t, stub)
668
669 //4. Test installation of EAPOL flows on specific ports
Manikkaraj kb1a10922019-07-29 12:10:34 -0400670 runInstallEapolFlows(t, stub, 0, 101, 102)
khenaidoo0458db62019-06-20 08:50:36 -0400671
672 lds, err := tu.ListLogicalDevices(stub)
673 assert.Nil(t, err)
674
675 //5. Test deletion of EAPOL on a specific port for a given logical device
Manikkaraj kb1a10922019-07-29 12:10:34 -0400676 runDeleteEapolFlows(t, stub, lds.Items[0], 0, 101)
677}
678
679// Meter Add Test
680func TestMeters(t *testing.T) {
681 //1. Start test for meter add
682 meterAdd(t, 1, 1600, 1600)
683 err := refreshLocalDeviceCache(stub)
684 assert.Nil(t, err)
685 verifyMeter(t, 1, 1600, 1600, 0)
686
687 //2. Start test for meter mod
688 meterMod(t, 1, 6400, 6400)
689 err = refreshLocalDeviceCache(stub)
690 assert.Nil(t, err)
691 verifyMeter(t, 1, 6400, 6400, 0)
692
693 //3. Start test for meter del
694 meterDel(t, 1)
695 err = refreshLocalDeviceCache(stub)
696 assert.Nil(t, err)
697 verifyNoMeters(t)
698}
699
700func TestFlowManagementWithMeters(t *testing.T) {
701 //1. Delete existing flows
702 for _, logicaldevice := range allLogicalDevices {
703 err := deleteAllFlows(stub, logicaldevice)
704 assert.Nil(t, err)
705 }
706 deleteAllMeters(t)
707 //2. Refresh the local cache so that the changes are reflected here
708 err := refreshLocalDeviceCache(stub)
709 assert.Nil(t, err)
710
711 //3. Add meter with ID
712 meterAdd(t, 1, 1600, 1600)
713
714 err = refreshLocalDeviceCache(stub)
715 assert.Nil(t, err)
716
717 //4. Verify that the meter is installed
718 verifyMeter(t, 1, 1600, 1600, 0)
719
720 //3. Test installation of EAPOL flows with meter (Add and verify the flow)
721 runInstallEapolFlows(t, stub, MeterIDStart)
722
723 //4. Test deletion of all EAPOL flows
724 runDeleteAllFlows(t, stub)
725
726 //5. Test installation of EAPOL flows on specific ports with meter (Add and verify the flows)
727 runInstallEapolFlows(t, stub, MeterIDStart, 101, 102)
728
729 lds, err := tu.ListLogicalDevices(stub)
730 assert.Nil(t, err)
731
732 //6. Test deletion of EAPOL on a specific port for a given logical device
733 runDeleteEapolFlows(t, stub, lds.Items[0], MeterIDStart, 101)
734}
735
736func TestMultipleMeterAddSequential(t *testing.T) {
737 //1. Delete existing flows
738 for _, logicaldevice := range allLogicalDevices {
739 err := deleteAllFlows(stub, logicaldevice)
740 assert.Nil(t, err)
741 }
742
743 // Delete All The Previously Installed Meters
744 deleteAllMeters(t)
745 // Verify that no meters are present
746 err := refreshLocalDeviceCache(stub)
747 assert.Nil(t, err)
748 verifyNoMeters(t)
749 //2. Add Meter Sequentially
750 // Here wait-group is not required, creating and passing wait-group only because the function addMultipleMeterSequentially
751 // expects wait group.
752 var wg sync.WaitGroup
753 wg.Add(1)
754 addMultipleMeterSequentially(t, MeterIDStart, MeterIDStop, 1600, 1600, &wg)
755
756 err = refreshLocalDeviceCache(stub)
757 assert.Nil(t, err)
758
759 //3. Verify that the meters are installed
760 for meterID := MeterIDStart; meterID <= MeterIDStop; meterID++ {
761 verifyMeter(t, uint32(meterID), 1600, 1600, 0)
762 }
763}
764
765func TestMeterDeleteParallel(t *testing.T) {
766 var wg sync.WaitGroup
767 wg.Add(4)
768 go delMultipleMeterSequential(t, MeterIDStart, MeterIDStop/4, &wg)
769 go delMultipleMeterSequential(t, MeterIDStop/4+1, (MeterIDStop / 2), &wg)
770 go delMultipleMeterSequential(t, (MeterIDStop/2)+1, MeterIDStop/4*3, &wg)
771 go delMultipleMeterSequential(t, (MeterIDStop/4*3)+1, MeterIDStop, &wg)
772 wg.Wait()
773
774 verifyNoMeters(t)
775}
776
777func TestMultipleMeterAddParallel(t *testing.T) {
778 err := refreshLocalDeviceCache(stub)
779 assert.Nil(t, err)
780
781 for _, logicaldevice := range allLogicalDevices {
782 err := deleteAllFlows(stub, logicaldevice)
783 assert.Nil(t, err)
784 }
785
786 var wg sync.WaitGroup
787 wg.Add(4)
788 go addMultipleMeterSequentially(t, MeterIDStart, (MeterIDStop / 4), 3200, 3200, &wg)
789 go addMultipleMeterSequentially(t, (MeterIDStop/4 + 1), MeterIDStop/2, 3200, 3200, &wg)
790 go addMultipleMeterSequentially(t, MeterIDStop/2+1, (MeterIDStop / 4 * 3), 3200, 3200, &wg)
791 go addMultipleMeterSequentially(t, (MeterIDStop/4*3)+1, MeterIDStop, 3200, 3200, &wg)
792
793 wg.Wait()
794
795 // Verify the devices
796 err = tu.VerifyDevices(stub, NumOfONUsPerOLT)
797 assert.Nil(t, err)
798
799 err = refreshLocalDeviceCache(stub)
800 assert.Nil(t, err)
801 for meterID := MeterIDStart; meterID <= MeterIDStop; meterID++ {
802 fmt.Println("Verifying meter ID :", meterID)
803 verifyMeter(t, uint32(meterID), 3200, 3200, 0)
804 }
805}
806
807func TestMultipleMeterModSequential(t *testing.T) {
808 var wg sync.WaitGroup
809 wg.Add(1)
810 //1. Modify all the existing meters
811 modMultipleMeterSequentially(t, MeterIDStart, MeterIDStop, 6400, 6400, &wg)
812 //2. Verify that the device state is proper after updating so many meters
813 err := tu.VerifyDevices(stub, NumOfONUsPerOLT)
814 assert.Nil(t, err)
815
816 //3. Refresh logical device cache
817 err = refreshLocalDeviceCache(stub)
818 assert.Nil(t, err)
819
820 //4. Verify that all the meters got modified
821 for meterID := MeterIDStart; meterID <= MeterIDStop; meterID++ {
822 fmt.Println("Verifying meter ID :", meterID)
823 verifyMeter(t, uint32(meterID), 6400, 6400, 0)
824 }
825}
826
827func TestMultipleMeterModParallel(t *testing.T) {
828 var wg sync.WaitGroup
829 wg.Add(4)
830 //1. Modify all the existing meters
831 go modMultipleMeterSequentially(t, MeterIDStart, MeterIDStop/4, 1600, 1600, &wg)
832 go modMultipleMeterSequentially(t, (MeterIDStop/4 + 1), MeterIDStop/2, 1600, 1600, &wg)
833 go modMultipleMeterSequentially(t, (MeterIDStop/2 + 1), (MeterIDStop / 4 * 3), 1600, 1600, &wg)
834 go modMultipleMeterSequentially(t, (MeterIDStop/4*3)+1, MeterIDStop, 1600, 1600, &wg)
835 //2. Verify that the device state is proper after updating so many meters
836 err := tu.VerifyDevices(stub, NumOfONUsPerOLT)
837 assert.Nil(t, err)
838 wg.Wait()
839
840 //3. Refresh logical device cache
841 err = refreshLocalDeviceCache(stub)
842 assert.Nil(t, err)
843
844 //4. Verify that all the meters got modified
845 for meterID := MeterIDStart; meterID <= MeterIDStop; meterID++ {
846 fmt.Println("Verifying meter ID :", meterID)
847 verifyMeter(t, uint32(meterID), 1600, 1600, 0)
848 }
849}
850
851func TestMultipleMeterDelSequential(t *testing.T) {
852 var wg sync.WaitGroup
853 wg.Add(1)
854 //1. Delete all the given meters sequentially
855 delMultipleMeterSequential(t, MeterIDStart, MeterIDStop, &wg)
856 //2. Verify that all the given meters are deleted
857 verifyNoMeters(t)
858}
859
860func TestMultipleFlowsWithMeters(t *testing.T) {
861 err := refreshLocalDeviceCache(stub)
862 assert.Nil(t, err)
863
864 //1. Delete all the previous flows
865 for _, lD := range allLogicalDevices {
866 deleteAllFlows(stub, lD)
867 }
868
869 //2. Add multiple meters for the flows to refer to
870 var wg sync.WaitGroup
871 wg.Add(2)
872 addMultipleMeterSequentially(t, MeterIDStart, 10, 1600, 1600, &wg)
873 // Adding meter verification here again will increase the time taken by the test. So leaving meter verification
874 installMultipleFlowsWithMeter(t, 1, 10, &wg)
875}
876
877func TestFlowDeletionWithMeterDelete(t *testing.T) {
878 err := refreshLocalDeviceCache(stub)
879 assert.Nil(t, err)
880
881 //1. Delete all meters
882 deleteAllMeters(t)
883 //2. Verify that all the meters are deleted
884 verifyNoMeters(t)
885 //3. As no meters are present, so all flows referring to these meters should also be deleted
886 // Flow referring to meterID 1 - 10 were installed in the above test "TestMultipleFlowsWithMeters"
887 err = refreshLocalDeviceCache(stub)
888 assert.Nil(t, err)
889 for _, lD := range allLogicalDevices {
890 verifyNOFlows(t, lD, 100, 101)
891 }
892}
893
894func TestAddFlowWithInvalidMeter(t *testing.T) {
895 var err error
896 for _, ld := range allLogicalDevices {
897 // Adding flows with meter-ID which is not present should throw error stating -
898 // "Meter-referred-by-flow-is-not-found-in-logicaldevice"
899 err = installEapolFlows(stub, ld, 1, 100, 101)
900 assert.NotNil(t, err)
901 }
khenaidoo0458db62019-06-20 08:50:36 -0400902}
903
904func TestMain(m *testing.M) {
905 setup()
906 code := m.Run()
907 shutdown()
908 os.Exit(code)
909}