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