blob: a6a4a1f0247d3019786c47c6b201395962812e49 [file] [log] [blame]
Matteo Scandolo256266d2020-06-01 13:44:07 -07001/*
Joey Armstrong03b20872024-01-12 13:03:07 -05002 * Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
Matteo Scandolo256266d2020-06-01 13:44:07 -07003
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 openflow
18
19import (
Rohan Agrawalc32d9932020-06-15 11:01:47 +000020 "context"
Matteo Scandolo256266d2020-06-01 13:44:07 -070021 "fmt"
Kent Hagerman9b0ac0a2020-06-08 11:48:16 -040022 "math"
23 "testing"
24
Matteo Scandolo256266d2020-06-01 13:44:07 -070025 "github.com/opencord/goloxi"
26 "github.com/opencord/goloxi/of13"
27 "github.com/opencord/ofagent-go/internal/pkg/holder"
28 "github.com/opencord/ofagent-go/internal/pkg/mock"
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000029 "github.com/opencord/voltha-protos/v5/go/openflow_13"
30 "github.com/opencord/voltha-protos/v5/go/voltha"
Matteo Scandolo256266d2020-06-01 13:44:07 -070031 "github.com/stretchr/testify/assert"
Matteo Scandolo256266d2020-06-01 13:44:07 -070032)
33
34var msgSizeLimit = 64000
35
36func createEapolFlow(id int) openflow_13.OfpFlowStats {
37
38 portField := openflow_13.OfpOxmField{
39 OxmClass: openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
40 Field: &openflow_13.OfpOxmField_OfbField{
41 OfbField: &openflow_13.OfpOxmOfbField{
42 Type: openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT,
43 Value: &openflow_13.OfpOxmOfbField_Port{Port: 16},
44 },
45 },
46 }
47
48 ethField := openflow_13.OfpOxmField{
49 OxmClass: openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
50 Field: &openflow_13.OfpOxmField_OfbField{
51 OfbField: &openflow_13.OfpOxmOfbField{
52 Type: openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE,
53 Value: &openflow_13.OfpOxmOfbField_EthType{EthType: 2048},
54 },
55 },
56 }
57
58 vlanField := openflow_13.OfpOxmField{
59 OxmClass: openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
60 Field: &openflow_13.OfpOxmField_OfbField{
61 OfbField: &openflow_13.OfpOxmOfbField{
62 Type: openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID,
63 Value: &openflow_13.OfpOxmOfbField_VlanVid{VlanVid: 4096},
64 },
65 },
66 }
67
68 return openflow_13.OfpFlowStats{
69 Id: uint64(id),
70 Priority: 10000,
71 Flags: 1,
72 Match: &openflow_13.OfpMatch{
73 Type: openflow_13.OfpMatchType_OFPMT_OXM,
74 OxmFields: []*openflow_13.OfpOxmField{
75 &portField, &ethField, &vlanField,
76 },
77 },
78 Instructions: []*openflow_13.OfpInstruction{
79 {
80 Type: uint32(openflow_13.OfpInstructionType_OFPIT_APPLY_ACTIONS),
81 Data: &openflow_13.OfpInstruction_Actions{
82 Actions: &openflow_13.OfpInstructionActions{
83 Actions: []*openflow_13.OfpAction{
84 {
85 Type: openflow_13.OfpActionType_OFPAT_OUTPUT,
86 Action: &openflow_13.OfpAction_Output{
87 Output: &openflow_13.OfpActionOutput{
88 Port: 4294967293,
89 },
90 },
91 },
92 },
93 },
94 },
95 },
96 {
97 Type: uint32(openflow_13.OfpInstructionType_OFPIT_WRITE_METADATA),
98 Data: &openflow_13.OfpInstruction_WriteMetadata{
99 WriteMetadata: &openflow_13.OfpInstructionWriteMetadata{
100 Metadata: 274877906944,
101 },
102 },
103 },
104 {
105 Type: uint32(openflow_13.OfpInstructionType_OFPIT_METER),
106 Data: &openflow_13.OfpInstruction_Meter{
107 Meter: &openflow_13.OfpInstructionMeter{
108 MeterId: 2,
109 },
110 },
111 },
112 },
113 }
114}
115
116func createRandomFlows(count int) []*openflow_13.OfpFlowStats {
117
118 var flows []*openflow_13.OfpFlowStats
119
120 n := 0
121 for n < count {
122
123 flow := createEapolFlow(n)
124
125 flows = append(flows, &flow)
126
Andrey Pozolotin536ee582021-05-28 16:31:44 +0300127 n++
Matteo Scandolo256266d2020-06-01 13:44:07 -0700128 }
129 return flows
130}
131
132func createRandomPorts(count int) []*voltha.LogicalPort {
133 var ports []*voltha.LogicalPort
134
135 n := 0
136 for n < count {
137
138 port := voltha.LogicalPort{
139 Id: fmt.Sprintf("uni-%d", n),
140 OfpPort: &openflow_13.OfpPort{
141 PortNo: uint32(n),
142 HwAddr: []uint32{8, 0, 0, 0, 0, uint32(n)},
143 Name: fmt.Sprintf("BBSM-%d", n),
144 State: uint32(openflow_13.OfpPortState_OFPPS_LIVE),
145 Curr: 4128,
146 Advertised: 4128,
147 Peer: 4128,
148 CurrSpeed: 32,
149 MaxSpeed: 32,
150 Config: 1,
151 Supported: 1,
152 },
153 }
154
155 ports = append(ports, &port)
156
Andrey Pozolotin536ee582021-05-28 16:31:44 +0300157 n++
Matteo Scandolo256266d2020-06-01 13:44:07 -0700158 }
159 return ports
160}
161
162func newTestOFConnection(flowsCount int, portsCount int) *OFConnection {
163
164 flows := openflow_13.Flows{
165 Items: createRandomFlows(flowsCount),
166 }
167
168 ports := voltha.LogicalPorts{
169 Items: createRandomPorts(portsCount),
170 }
171
Matteo Scandolo256266d2020-06-01 13:44:07 -0700172 volthaClient := mock.MockVolthaClient{
173 LogicalDeviceFlows: flows,
174 LogicalPorts: ports,
Matteo Scandolo256266d2020-06-01 13:44:07 -0700175 }
176
177 volthaClientHolder := &holder.VolthaServiceClientHolder{}
178 volthaClientHolder.Set(volthaClient)
179
180 return &OFConnection{
181 VolthaClient: volthaClientHolder,
182 flowsChunkSize: ofcFlowsChunkSize,
183 portsChunkSize: ofcPortsChunkSize,
184 portsDescChunkSize: ofcPortsDescChunkSize,
185 }
186}
187
Andrea Campanellaf2cf13e2020-09-03 16:22:27 +0200188func TestHandleFlowStatsRequestExactlyDivisible(t *testing.T) {
Matteo Scandolo256266d2020-06-01 13:44:07 -0700189
Andrea Campanellaf2cf13e2020-09-03 16:22:27 +0200190 generatedFlowsCount := ofcFlowsChunkSize * 5
Matteo Scandolo256266d2020-06-01 13:44:07 -0700191
Andrea Campanellaf2cf13e2020-09-03 16:22:27 +0200192 testCorrectChunkAndReplyMoreFlag(t, generatedFlowsCount)
193}
Matteo Scandolo256266d2020-06-01 13:44:07 -0700194
Andrea Campanellaf2cf13e2020-09-03 16:22:27 +0200195func TestHandleFlowStatsRequestNotExactlyDivisible(t *testing.T) {
196
197 generatedFlowsCount := int(ofcFlowsChunkSize * 5.5)
198
199 testCorrectChunkAndReplyMoreFlag(t, generatedFlowsCount)
200}
201
202func testCorrectChunkAndReplyMoreFlag(t *testing.T, generatedFlowsCount int) {
203 ofc := newTestOFConnection(generatedFlowsCount, 0)
Matteo Scandolo256266d2020-06-01 13:44:07 -0700204 request := of13.NewFlowStatsRequest()
Rohan Agrawalc32d9932020-06-15 11:01:47 +0000205 replies, err := ofc.handleFlowStatsRequest(context.Background(), request)
Matteo Scandolo256266d2020-06-01 13:44:07 -0700206 assert.Equal(t, err, nil)
Matteo Scandolo256266d2020-06-01 13:44:07 -0700207 // check that the correct number of messages is generated
208 assert.Equal(t, int(math.Ceil(float64(generatedFlowsCount)/ofcFlowsChunkSize)), len(replies))
Matteo Scandolo256266d2020-06-01 13:44:07 -0700209 n := 1
210 entriesCount := 0
Matteo Scandolo256266d2020-06-01 13:44:07 -0700211 for _, r := range replies {
212 json, _ := r.Flags.MarshalJSON()
213
214 // check that the ReplyMore flag is correctly set in the messages
215 if n == len(replies) {
216 assert.Equal(t, string(json), "{}")
217 } else {
218 assert.Equal(t, string(json), "{\"OFPSFReplyMore\": true}")
219 }
220
221 // check the message size
222 enc := goloxi.NewEncoder()
223 if err := r.Serialize(enc); err != nil {
224 t.Fail()
225 }
226 bytes := enc.Bytes()
227 fmt.Println("FlowStats msg size: ", len(bytes))
228 if len(bytes) > msgSizeLimit {
229 t.Fatal("Message size is bigger than 64KB")
230 }
231
Andrey Pozolotin536ee582021-05-28 16:31:44 +0300232 entriesCount += len(r.GetEntries())
Matteo Scandolo256266d2020-06-01 13:44:07 -0700233 n++
234 }
Matteo Scandolo256266d2020-06-01 13:44:07 -0700235 // make sure all the generate item are included in the responses
236 assert.Equal(t, generatedFlowsCount, entriesCount)
237}
238
239func TestHandlePortStatsRequest(t *testing.T) {
240
241 generatedPortsCount := 2560
242
243 ofc := newTestOFConnection(0, generatedPortsCount)
244
245 request := of13.NewPortStatsRequest()
246
247 // request stats for all ports
248 request.PortNo = 0xffffffff
249
Girish Kumar01e0c632020-08-10 16:48:56 +0000250 replies, err := ofc.handlePortStatsRequest(context.Background(), request)
Matteo Scandolo256266d2020-06-01 13:44:07 -0700251 assert.Equal(t, err, nil)
252
253 assert.Equal(t, int(math.Ceil(float64(generatedPortsCount)/ofcPortsChunkSize)), len(replies))
254
255 n := 1
256 entriesCount := 0
257
258 for _, r := range replies {
259 json, _ := r.Flags.MarshalJSON()
260
261 // check that the ReplyMore flag is correctly set in the messages
262 if n == len(replies) {
263 assert.Equal(t, string(json), "{}")
264 } else {
265 assert.Equal(t, string(json), "{\"OFPSFReplyMore\": true}")
266 }
267
268 // check the message size
269 enc := goloxi.NewEncoder()
270 if err := r.Serialize(enc); err != nil {
271 t.Fail()
272 }
273 bytes := enc.Bytes()
274 fmt.Println("PortStats msg size: ", len(bytes))
275 if len(bytes) > msgSizeLimit {
276 t.Fatal("Message size is bigger than 64KB")
277 }
278
Andrey Pozolotin536ee582021-05-28 16:31:44 +0300279 entriesCount += len(r.GetEntries())
Matteo Scandolo256266d2020-06-01 13:44:07 -0700280 n++
281 }
282
283 // make sure all the generate item are included in the responses
284 assert.Equal(t, generatedPortsCount, entriesCount)
285}
286
287func TestHandlePortDescStatsRequest(t *testing.T) {
288
289 generatedPortsCount := 2560
290
291 ofc := newTestOFConnection(0, generatedPortsCount)
292
293 request := of13.NewPortDescStatsRequest()
294
Girish Kumar01e0c632020-08-10 16:48:56 +0000295 replies, err := ofc.handlePortDescStatsRequest(context.Background(), request)
Matteo Scandolo256266d2020-06-01 13:44:07 -0700296 assert.Equal(t, err, nil)
297
298 // check that the correct number of messages is generated
299 assert.Equal(t, int(math.Ceil(float64(generatedPortsCount)/ofcPortsDescChunkSize)), len(replies))
300
301 n := 1
302 entriesCount := 0
303
304 for _, r := range replies {
305 json, _ := r.Flags.MarshalJSON()
306
307 // check that the ReplyMore flag is correctly set in the messages
308 if n == len(replies) {
309 assert.Equal(t, string(json), "{}")
310 } else {
311 assert.Equal(t, string(json), "{\"OFPSFReplyMore\": true}")
312 }
313
314 // check the message size
315 enc := goloxi.NewEncoder()
316 if err := r.Serialize(enc); err != nil {
317 t.Fail()
318 }
319 bytes := enc.Bytes()
320 fmt.Println("PortDesc msg size: ", len(bytes))
321 if len(bytes) > msgSizeLimit {
322 t.Fatal("Message size is bigger than 64KB")
323 }
324
Andrey Pozolotin536ee582021-05-28 16:31:44 +0300325 entriesCount += len(r.GetEntries())
Matteo Scandolo256266d2020-06-01 13:44:07 -0700326 n++
327 }
328
329 // make sure all the generate item are included in the responses
330 assert.Equal(t, generatedPortsCount, entriesCount)
331}