blob: 05273bfc4f40199565f172f461a8c153a1c75a8a [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 (
20 "fmt"
Kent Hagerman9b0ac0a2020-06-08 11:48:16 -040021 "math"
22 "testing"
23
Matteo Scandolo256266d2020-06-01 13:44:07 -070024 "github.com/opencord/goloxi"
25 "github.com/opencord/goloxi/of13"
26 "github.com/opencord/ofagent-go/internal/pkg/holder"
27 "github.com/opencord/ofagent-go/internal/pkg/mock"
28 "github.com/opencord/voltha-protos/v3/go/openflow_13"
29 "github.com/opencord/voltha-protos/v3/go/voltha"
30 "github.com/stretchr/testify/assert"
Matteo Scandolo256266d2020-06-01 13:44:07 -070031)
32
33var msgSizeLimit = 64000
34
35func createEapolFlow(id int) openflow_13.OfpFlowStats {
36
37 portField := openflow_13.OfpOxmField{
38 OxmClass: openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
39 Field: &openflow_13.OfpOxmField_OfbField{
40 OfbField: &openflow_13.OfpOxmOfbField{
41 Type: openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT,
42 Value: &openflow_13.OfpOxmOfbField_Port{Port: 16},
43 },
44 },
45 }
46
47 ethField := openflow_13.OfpOxmField{
48 OxmClass: openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
49 Field: &openflow_13.OfpOxmField_OfbField{
50 OfbField: &openflow_13.OfpOxmOfbField{
51 Type: openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE,
52 Value: &openflow_13.OfpOxmOfbField_EthType{EthType: 2048},
53 },
54 },
55 }
56
57 vlanField := openflow_13.OfpOxmField{
58 OxmClass: openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
59 Field: &openflow_13.OfpOxmField_OfbField{
60 OfbField: &openflow_13.OfpOxmOfbField{
61 Type: openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID,
62 Value: &openflow_13.OfpOxmOfbField_VlanVid{VlanVid: 4096},
63 },
64 },
65 }
66
67 return openflow_13.OfpFlowStats{
68 Id: uint64(id),
69 Priority: 10000,
70 Flags: 1,
71 Match: &openflow_13.OfpMatch{
72 Type: openflow_13.OfpMatchType_OFPMT_OXM,
73 OxmFields: []*openflow_13.OfpOxmField{
74 &portField, &ethField, &vlanField,
75 },
76 },
77 Instructions: []*openflow_13.OfpInstruction{
78 {
79 Type: uint32(openflow_13.OfpInstructionType_OFPIT_APPLY_ACTIONS),
80 Data: &openflow_13.OfpInstruction_Actions{
81 Actions: &openflow_13.OfpInstructionActions{
82 Actions: []*openflow_13.OfpAction{
83 {
84 Type: openflow_13.OfpActionType_OFPAT_OUTPUT,
85 Action: &openflow_13.OfpAction_Output{
86 Output: &openflow_13.OfpActionOutput{
87 Port: 4294967293,
88 },
89 },
90 },
91 },
92 },
93 },
94 },
95 {
96 Type: uint32(openflow_13.OfpInstructionType_OFPIT_WRITE_METADATA),
97 Data: &openflow_13.OfpInstruction_WriteMetadata{
98 WriteMetadata: &openflow_13.OfpInstructionWriteMetadata{
99 Metadata: 274877906944,
100 },
101 },
102 },
103 {
104 Type: uint32(openflow_13.OfpInstructionType_OFPIT_METER),
105 Data: &openflow_13.OfpInstruction_Meter{
106 Meter: &openflow_13.OfpInstructionMeter{
107 MeterId: 2,
108 },
109 },
110 },
111 },
112 }
113}
114
115func createRandomFlows(count int) []*openflow_13.OfpFlowStats {
116
117 var flows []*openflow_13.OfpFlowStats
118
119 n := 0
120 for n < count {
121
122 flow := createEapolFlow(n)
123
124 flows = append(flows, &flow)
125
126 n = n + 1
127 }
128 return flows
129}
130
131func createRandomPorts(count int) []*voltha.LogicalPort {
132 var ports []*voltha.LogicalPort
133
134 n := 0
135 for n < count {
136
137 port := voltha.LogicalPort{
138 Id: fmt.Sprintf("uni-%d", n),
139 OfpPort: &openflow_13.OfpPort{
140 PortNo: uint32(n),
141 HwAddr: []uint32{8, 0, 0, 0, 0, uint32(n)},
142 Name: fmt.Sprintf("BBSM-%d", n),
143 State: uint32(openflow_13.OfpPortState_OFPPS_LIVE),
144 Curr: 4128,
145 Advertised: 4128,
146 Peer: 4128,
147 CurrSpeed: 32,
148 MaxSpeed: 32,
149 Config: 1,
150 Supported: 1,
151 },
152 }
153
154 ports = append(ports, &port)
155
156 n = n + 1
157 }
158 return ports
159}
160
161func newTestOFConnection(flowsCount int, portsCount int) *OFConnection {
162
163 flows := openflow_13.Flows{
164 Items: createRandomFlows(flowsCount),
165 }
166
167 ports := voltha.LogicalPorts{
168 Items: createRandomPorts(portsCount),
169 }
170
Matteo Scandolo256266d2020-06-01 13:44:07 -0700171 volthaClient := mock.MockVolthaClient{
172 LogicalDeviceFlows: flows,
173 LogicalPorts: ports,
Matteo Scandolo256266d2020-06-01 13:44:07 -0700174 }
175
176 volthaClientHolder := &holder.VolthaServiceClientHolder{}
177 volthaClientHolder.Set(volthaClient)
178
179 return &OFConnection{
180 VolthaClient: volthaClientHolder,
181 flowsChunkSize: ofcFlowsChunkSize,
182 portsChunkSize: ofcPortsChunkSize,
183 portsDescChunkSize: ofcPortsDescChunkSize,
184 }
185}
186
187func TestHandleFlowStatsRequest(t *testing.T) {
188
189 generatedFlowsCount := 2000
190
191 ofc := newTestOFConnection(2000, 0)
192
193 request := of13.NewFlowStatsRequest()
194
195 replies, err := ofc.handleFlowStatsRequest(request)
196 assert.Equal(t, err, nil)
197
198 // check that the correct number of messages is generated
199 assert.Equal(t, int(math.Ceil(float64(generatedFlowsCount)/ofcFlowsChunkSize)), len(replies))
200
201 n := 1
202 entriesCount := 0
203
204 for _, r := range replies {
205 json, _ := r.Flags.MarshalJSON()
206
207 // check that the ReplyMore flag is correctly set in the messages
208 if n == len(replies) {
209 assert.Equal(t, string(json), "{}")
210 } else {
211 assert.Equal(t, string(json), "{\"OFPSFReplyMore\": true}")
212 }
213
214 // check the message size
215 enc := goloxi.NewEncoder()
216 if err := r.Serialize(enc); err != nil {
217 t.Fail()
218 }
219 bytes := enc.Bytes()
220 fmt.Println("FlowStats msg size: ", len(bytes))
221 if len(bytes) > msgSizeLimit {
222 t.Fatal("Message size is bigger than 64KB")
223 }
224
225 entriesCount = entriesCount + len(r.GetEntries())
226 n++
227 }
228
229 // make sure all the generate item are included in the responses
230 assert.Equal(t, generatedFlowsCount, entriesCount)
231}
232
233func TestHandlePortStatsRequest(t *testing.T) {
234
235 generatedPortsCount := 2560
236
237 ofc := newTestOFConnection(0, generatedPortsCount)
238
239 request := of13.NewPortStatsRequest()
240
241 // request stats for all ports
242 request.PortNo = 0xffffffff
243
244 replies, err := ofc.handlePortStatsRequest(request)
245 assert.Equal(t, err, nil)
246
247 assert.Equal(t, int(math.Ceil(float64(generatedPortsCount)/ofcPortsChunkSize)), len(replies))
248
249 n := 1
250 entriesCount := 0
251
252 for _, r := range replies {
253 json, _ := r.Flags.MarshalJSON()
254
255 // check that the ReplyMore flag is correctly set in the messages
256 if n == len(replies) {
257 assert.Equal(t, string(json), "{}")
258 } else {
259 assert.Equal(t, string(json), "{\"OFPSFReplyMore\": true}")
260 }
261
262 // check the message size
263 enc := goloxi.NewEncoder()
264 if err := r.Serialize(enc); err != nil {
265 t.Fail()
266 }
267 bytes := enc.Bytes()
268 fmt.Println("PortStats msg size: ", len(bytes))
269 if len(bytes) > msgSizeLimit {
270 t.Fatal("Message size is bigger than 64KB")
271 }
272
273 entriesCount = entriesCount + len(r.GetEntries())
274 n++
275 }
276
277 // make sure all the generate item are included in the responses
278 assert.Equal(t, generatedPortsCount, entriesCount)
279}
280
281func TestHandlePortDescStatsRequest(t *testing.T) {
282
283 generatedPortsCount := 2560
284
285 ofc := newTestOFConnection(0, generatedPortsCount)
286
287 request := of13.NewPortDescStatsRequest()
288
289 replies, err := ofc.handlePortDescStatsRequest(request)
290 assert.Equal(t, err, nil)
291
292 // check that the correct number of messages is generated
293 assert.Equal(t, int(math.Ceil(float64(generatedPortsCount)/ofcPortsDescChunkSize)), len(replies))
294
295 n := 1
296 entriesCount := 0
297
298 for _, r := range replies {
299 json, _ := r.Flags.MarshalJSON()
300
301 // check that the ReplyMore flag is correctly set in the messages
302 if n == len(replies) {
303 assert.Equal(t, string(json), "{}")
304 } else {
305 assert.Equal(t, string(json), "{\"OFPSFReplyMore\": true}")
306 }
307
308 // check the message size
309 enc := goloxi.NewEncoder()
310 if err := r.Serialize(enc); err != nil {
311 t.Fail()
312 }
313 bytes := enc.Bytes()
314 fmt.Println("PortDesc msg size: ", len(bytes))
315 if len(bytes) > msgSizeLimit {
316 t.Fatal("Message size is bigger than 64KB")
317 }
318
319 entriesCount = entriesCount + len(r.GetEntries())
320 n++
321 }
322
323 // make sure all the generate item are included in the responses
324 assert.Equal(t, generatedPortsCount, entriesCount)
325}