blob: e80d23990aead2b6f1d6c47bd1eed0107866ba83 [file] [log] [blame]
Matteo Scandolo256266d2020-06-01 13:44:07 -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 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"
29 "github.com/opencord/voltha-protos/v3/go/openflow_13"
30 "github.com/opencord/voltha-protos/v3/go/voltha"
31 "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
127 n = n + 1
128 }
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
157 n = n + 1
158 }
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
188func TestHandleFlowStatsRequest(t *testing.T) {
189
190 generatedFlowsCount := 2000
191
192 ofc := newTestOFConnection(2000, 0)
193
194 request := of13.NewFlowStatsRequest()
195
Rohan Agrawalc32d9932020-06-15 11:01:47 +0000196 replies, err := ofc.handleFlowStatsRequest(context.Background(), request)
Matteo Scandolo256266d2020-06-01 13:44:07 -0700197 assert.Equal(t, err, nil)
198
199 // check that the correct number of messages is generated
200 assert.Equal(t, int(math.Ceil(float64(generatedFlowsCount)/ofcFlowsChunkSize)), len(replies))
201
202 n := 1
203 entriesCount := 0
204
205 for _, r := range replies {
206 json, _ := r.Flags.MarshalJSON()
207
208 // check that the ReplyMore flag is correctly set in the messages
209 if n == len(replies) {
210 assert.Equal(t, string(json), "{}")
211 } else {
212 assert.Equal(t, string(json), "{\"OFPSFReplyMore\": true}")
213 }
214
215 // check the message size
216 enc := goloxi.NewEncoder()
217 if err := r.Serialize(enc); err != nil {
218 t.Fail()
219 }
220 bytes := enc.Bytes()
221 fmt.Println("FlowStats msg size: ", len(bytes))
222 if len(bytes) > msgSizeLimit {
223 t.Fatal("Message size is bigger than 64KB")
224 }
225
226 entriesCount = entriesCount + len(r.GetEntries())
227 n++
228 }
229
230 // make sure all the generate item are included in the responses
231 assert.Equal(t, generatedFlowsCount, entriesCount)
232}
233
234func TestHandlePortStatsRequest(t *testing.T) {
235
236 generatedPortsCount := 2560
237
238 ofc := newTestOFConnection(0, generatedPortsCount)
239
240 request := of13.NewPortStatsRequest()
241
242 // request stats for all ports
243 request.PortNo = 0xffffffff
244
Girish Kumar01e0c632020-08-10 16:48:56 +0000245 replies, err := ofc.handlePortStatsRequest(context.Background(), request)
Matteo Scandolo256266d2020-06-01 13:44:07 -0700246 assert.Equal(t, err, nil)
247
248 assert.Equal(t, int(math.Ceil(float64(generatedPortsCount)/ofcPortsChunkSize)), len(replies))
249
250 n := 1
251 entriesCount := 0
252
253 for _, r := range replies {
254 json, _ := r.Flags.MarshalJSON()
255
256 // check that the ReplyMore flag is correctly set in the messages
257 if n == len(replies) {
258 assert.Equal(t, string(json), "{}")
259 } else {
260 assert.Equal(t, string(json), "{\"OFPSFReplyMore\": true}")
261 }
262
263 // check the message size
264 enc := goloxi.NewEncoder()
265 if err := r.Serialize(enc); err != nil {
266 t.Fail()
267 }
268 bytes := enc.Bytes()
269 fmt.Println("PortStats msg size: ", len(bytes))
270 if len(bytes) > msgSizeLimit {
271 t.Fatal("Message size is bigger than 64KB")
272 }
273
274 entriesCount = entriesCount + len(r.GetEntries())
275 n++
276 }
277
278 // make sure all the generate item are included in the responses
279 assert.Equal(t, generatedPortsCount, entriesCount)
280}
281
282func TestHandlePortDescStatsRequest(t *testing.T) {
283
284 generatedPortsCount := 2560
285
286 ofc := newTestOFConnection(0, generatedPortsCount)
287
288 request := of13.NewPortDescStatsRequest()
289
Girish Kumar01e0c632020-08-10 16:48:56 +0000290 replies, err := ofc.handlePortDescStatsRequest(context.Background(), request)
Matteo Scandolo256266d2020-06-01 13:44:07 -0700291 assert.Equal(t, err, nil)
292
293 // check that the correct number of messages is generated
294 assert.Equal(t, int(math.Ceil(float64(generatedPortsCount)/ofcPortsDescChunkSize)), len(replies))
295
296 n := 1
297 entriesCount := 0
298
299 for _, r := range replies {
300 json, _ := r.Flags.MarshalJSON()
301
302 // check that the ReplyMore flag is correctly set in the messages
303 if n == len(replies) {
304 assert.Equal(t, string(json), "{}")
305 } else {
306 assert.Equal(t, string(json), "{\"OFPSFReplyMore\": true}")
307 }
308
309 // check the message size
310 enc := goloxi.NewEncoder()
311 if err := r.Serialize(enc); err != nil {
312 t.Fail()
313 }
314 bytes := enc.Bytes()
315 fmt.Println("PortDesc msg size: ", len(bytes))
316 if len(bytes) > msgSizeLimit {
317 t.Fatal("Message size is bigger than 64KB")
318 }
319
320 entriesCount = entriesCount + len(r.GetEntries())
321 n++
322 }
323
324 // make sure all the generate item are included in the responses
325 assert.Equal(t, generatedPortsCount, entriesCount)
326}