Fix bug 1941 - Deleting of flows very slow with large number of flows
[openflowplugin.git] / openflowplugin / src / test / java / org / opendaylight / openflowplugin / openflow / md / util / FlowCreatorUtilTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.openflowplugin.openflow.md.util;
9
10 import static junit.framework.Assert.assertEquals;
11 import static junit.framework.Assert.assertFalse;
12 import static junit.framework.Assert.assertTrue;
13
14 import java.math.BigInteger;
15
16 import org.junit.Test;
17 import org.opendaylight.openflowplugin.api.OFConstants;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OxmMatchType;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.match.grouping.Match;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.match.v10.grouping.MatchV10;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.aggregate._case.MultipartRequestAggregate;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.aggregate._case.MultipartRequestAggregateBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.flow._case.MultipartRequestFlow;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.flow._case.MultipartRequestFlowBuilder;
37
38 public class FlowCreatorUtilTest {
39
40     private static final MacAddress macAddress = new MacAddress("00:00:00:00:00:00");
41     private static final Ipv4Address ipv4Address = new Ipv4Address("0.0.0.0");
42
43     /**
44      * Test method for {@link FlowCreatorUtil#setWildcardedFlowMatch(short version, MultipartRequestFlowBuilder flowBuilder)}.
45      */
46     @Test
47     public void testSetWildcardedFlowMatch_1_0() {
48         MultipartRequestFlowBuilder multipartRequestFlowBuilder = new MultipartRequestFlowBuilder();
49         FlowCreatorUtil.setWildcardedFlowMatch(OFConstants.OFP_VERSION_1_0, multipartRequestFlowBuilder);
50         MultipartRequestFlow multipartRequestFlow = multipartRequestFlowBuilder.build();
51         assertMatch(multipartRequestFlow.getMatchV10());
52
53         multipartRequestFlowBuilder = new MultipartRequestFlowBuilder();
54         FlowCreatorUtil.setWildcardedFlowMatch(OFConstants.OFP_VERSION_1_3, multipartRequestFlowBuilder);
55         multipartRequestFlow = multipartRequestFlowBuilder.build();
56         assertMatch(multipartRequestFlow.getMatch());
57     }
58
59     /**
60      * Test method for {@link FlowCreatorUtil#setWildcardedFlowMatch(short version, MultipartRequestAggregateBuilder aggregateBuilder)}.
61      */
62     @Test
63     public void testSetWildcardedFlowMatch_() {
64         MultipartRequestAggregateBuilder multipartRequestAggregateBuilder = new MultipartRequestAggregateBuilder();
65         FlowCreatorUtil.setWildcardedFlowMatch(OFConstants.OFP_VERSION_1_0, multipartRequestAggregateBuilder);
66         MultipartRequestAggregate multipartRequestAggregate = multipartRequestAggregateBuilder.build();
67         assertMatch(multipartRequestAggregate.getMatchV10());
68
69         multipartRequestAggregateBuilder = new MultipartRequestAggregateBuilder();
70         FlowCreatorUtil.setWildcardedFlowMatch(OFConstants.OFP_VERSION_1_3, multipartRequestAggregateBuilder);
71         multipartRequestAggregate = multipartRequestAggregateBuilder.build();
72         assertMatch(multipartRequestAggregate.getMatch());
73
74
75     }
76
77     /**
78      * Test method for
79      * {@link FlowCreatorUtil#canModifyFlow(OriginalFlow, UpdatedFlow, Short)}.
80      */
81     @Test
82     public void testCanModifyFlow() {
83         final Short of10 = Short.valueOf(OFConstants.OFP_VERSION_1_0);
84         final Short of13 = Short.valueOf(OFConstants.OFP_VERSION_1_3);
85         final Short[] versions = {null, of10, of13};
86         final Boolean[] bools = {null, Boolean.TRUE, Boolean.FALSE};
87
88         final Integer defPri = Integer.valueOf(0x8000);
89         final Integer defIdle = Integer.valueOf(300);
90         final Integer defHard = Integer.valueOf(600);
91         final FlowModFlags defFlags = FlowModFlags.getDefaultInstance("sENDFLOWREM");
92         final FlowModFlags flags = new FlowModFlags(false, true, false, true, false);
93         final FlowCookie defCookie = new FlowCookie(BigInteger.ZERO);
94         final FlowCookie cookie = new FlowCookie(BigInteger.valueOf(0x12345L));
95         final FlowCookie cookie1 = new FlowCookie(BigInteger.valueOf(0x67890L));
96         final FlowCookie cookieMask = new FlowCookie(BigInteger.valueOf(0xffff00L));
97
98         for (final Short ver: versions) {
99             final OriginalFlowBuilder originalBuilder = new OriginalFlowBuilder();
100             final UpdatedFlowBuilder updatedBuilder = new UpdatedFlowBuilder();
101             canModifyFlowTest(true, originalBuilder, updatedBuilder, ver);
102
103             // Default value tests.
104             canModifyFlowTest(true,
105                               new OriginalFlowBuilder().setPriority(defPri),
106                               updatedBuilder, ver);
107             canModifyFlowTest(true, originalBuilder,
108                               new UpdatedFlowBuilder().setPriority(defPri),
109                               ver);
110             canModifyFlowTest(true,
111                               new OriginalFlowBuilder().setIdleTimeout(defIdle),
112                               updatedBuilder, ver);
113             canModifyFlowTest(true, originalBuilder,
114                               new UpdatedFlowBuilder().setIdleTimeout(defIdle),
115                               ver);
116             canModifyFlowTest(true,
117                               new OriginalFlowBuilder().setHardTimeout(defHard),
118                               updatedBuilder, ver);
119             canModifyFlowTest(true, originalBuilder,
120                               new UpdatedFlowBuilder().setHardTimeout(defHard),
121                               ver);
122             canModifyFlowTest(false,
123                               new OriginalFlowBuilder().setFlags(defFlags),
124                               updatedBuilder, ver);
125             canModifyFlowTest(false, originalBuilder,
126                               new UpdatedFlowBuilder().setFlags(defFlags),
127                               ver);
128             canModifyFlowTest(true,
129                               new OriginalFlowBuilder().setCookie(defCookie),
130                               updatedBuilder, ver);
131             canModifyFlowTest(true, originalBuilder,
132                               new UpdatedFlowBuilder().setCookie(defCookie),
133                               ver);
134
135             // Set non-default values.
136             canModifyFlowTest(true,
137                               originalBuilder.setMatch(createMatch(0x800L)),
138                               updatedBuilder.setMatch(createMatch(0x800L)),
139                               ver);
140             canModifyFlowTest(true, originalBuilder.setIdleTimeout(600),
141                               updatedBuilder.setIdleTimeout(600), ver);
142             canModifyFlowTest(true, originalBuilder.setHardTimeout(1200),
143                               updatedBuilder.setHardTimeout(1200), ver);
144             canModifyFlowTest(true, originalBuilder.setPriority(100),
145                               updatedBuilder.setPriority(100), ver);
146             canModifyFlowTest(true, originalBuilder.setFlags(flags),
147                               updatedBuilder.setFlags(flags), ver);
148             canModifyFlowTest(true, originalBuilder.setCookie(cookie),
149                               updatedBuilder.setCookie(cookie), ver);
150
151             final OriginalFlow org = originalBuilder.build();
152             final UpdatedFlow upd = updatedBuilder.build();
153
154             // Set different match.
155             final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match[] matches = {null, createMatch(0x86ddL)};
156             for (final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match m: matches) {
157                 canModifyFlowTest(false, originalBuilder,
158                                   new UpdatedFlowBuilder(upd).setMatch(m),
159                                   ver);
160                 canModifyFlowTest(false,
161                                   new OriginalFlowBuilder(org).setMatch(m),
162                                   updatedBuilder, ver);
163             }
164
165             // Set different idle-timeout, hard-timeout, priority.
166             final Integer[] integers = {null, Integer.valueOf(3600)};
167             for (final Integer i: integers) {
168                 canModifyFlowTest(false, originalBuilder,
169                                   new UpdatedFlowBuilder(upd).setIdleTimeout(i),
170                                   ver);
171                 canModifyFlowTest(false,
172                                   new OriginalFlowBuilder(org).setIdleTimeout(i),
173                                   updatedBuilder, ver);
174
175                 canModifyFlowTest(false, originalBuilder,
176                                   new UpdatedFlowBuilder(upd).setHardTimeout(i),
177                                   ver);
178                 canModifyFlowTest(false,
179                                   new OriginalFlowBuilder(org).setHardTimeout(i),
180                                   updatedBuilder, ver);
181
182                 canModifyFlowTest(false, originalBuilder,
183                                   new UpdatedFlowBuilder(upd).setPriority(i),
184                                   ver);
185                 canModifyFlowTest(false,
186                                   new OriginalFlowBuilder(org).setPriority(i),
187                                   updatedBuilder, ver);
188             }
189
190             // Set different FLOW_MOD flags.
191             final FlowModFlags[] flowModFlags = {
192                 null,
193                 defFlags,
194                 new FlowModFlags(true, true, true, true, true),
195             };
196             for (final FlowModFlags f: flowModFlags) {
197                 canModifyFlowTest(false, originalBuilder,
198                                   new UpdatedFlowBuilder(upd).setFlags(f),
199                                   ver);
200                 canModifyFlowTest(false,
201                                   new OriginalFlowBuilder(org).setFlags(f),
202                                   updatedBuilder, ver);
203             }
204
205             // Set different cookie.
206             final FlowCookie[] cookies = {
207                 null,
208                 defCookie,
209                 new FlowCookie(BigInteger.valueOf(0x123456L)),
210             };
211             for (final FlowCookie c: cookies) {
212                 canModifyFlowTest(false, originalBuilder,
213                                   new UpdatedFlowBuilder(upd).setCookie(c),
214                                   ver);
215                 canModifyFlowTest(false,
216                                   new OriginalFlowBuilder(org).setCookie(c),
217                                   updatedBuilder, ver);
218             }
219
220             // Cookie mask test.
221             // Cookie mask is used by OF13 non-strict MODIFY command.
222             updatedBuilder.setCookie(cookie1);
223             for (final Boolean strict: bools) {
224                 updatedBuilder.setCookieMask(null).setStrict(strict);
225                 canModifyFlowTest(false, originalBuilder, updatedBuilder, ver);
226
227                 updatedBuilder.setCookieMask(defCookie);
228                 canModifyFlowTest(false, originalBuilder, updatedBuilder, ver);
229
230                 updatedBuilder.setCookieMask(cookieMask);
231                 final boolean expected = (of13.equals(ver) &&
232                                     !Boolean.TRUE.equals(strict));
233                 canModifyFlowTest(expected, originalBuilder, updatedBuilder,
234                                   ver);
235             }
236         }
237     }
238
239     /**
240      * Test method for
241      * {@link FlowCreatorUtil#equalsFlowModFlags(FlowModFlags, FlowModFlags)}.
242      */
243     @SuppressWarnings("deprecation")
244     @Test
245     public void testEqualsFlowModFlags() {
246         final FlowModFlags[] defaults = {
247             null,
248             new FlowModFlags(false, false, false, false, false),
249             new FlowModFlags(false, null, false, null, Boolean.FALSE),
250         };
251         final FlowModFlags all = new FlowModFlags(true, true, true, true, true);
252         final FlowModFlags none = new FlowModFlags(null, null, null, null, null);
253
254         for (final FlowModFlags f: defaults) {
255             assertTrue(FlowCreatorUtil.
256                        equalsFlowModFlags(f, (FlowModFlags)null));
257             assertTrue(FlowCreatorUtil.
258                        equalsFlowModFlags((FlowModFlags)null, f));
259             assertFalse(FlowCreatorUtil.
260                         equalsFlowModFlags((FlowModFlags)null, all));
261             assertFalse(FlowCreatorUtil.
262                         equalsFlowModFlags(all, (FlowModFlags)null));
263             assertTrue(FlowCreatorUtil.
264                         equalsFlowModFlags((FlowModFlags)null, none));
265             assertTrue(FlowCreatorUtil.
266                         equalsFlowModFlags(none, (FlowModFlags)null));
267         }
268
269         final String[] bitNames = {
270             "cHECKOVERLAP",
271             "nOBYTCOUNTS",
272             "nOPKTCOUNTS",
273             "rESETCOUNTS",
274             "sENDFLOWREM"
275         };
276         int bit = 0;
277         for (final String name: bitNames) {
278             final FlowModFlags flags = FlowModFlags.getDefaultInstance(name);
279             assertFalse(FlowCreatorUtil.equalsFlowModFlags(flags, all));
280             assertFalse(FlowCreatorUtil.equalsFlowModFlags(all, flags));
281             assertFalse(FlowCreatorUtil.equalsFlowModFlags(flags, none));
282             assertFalse(FlowCreatorUtil.equalsFlowModFlags(none, flags));
283
284             for (final String nm: bitNames) {
285                 final FlowModFlags f = FlowModFlags.getDefaultInstance(nm);
286                 final boolean expected = nm.equals(name);
287                 assertEquals(expected,
288                              FlowCreatorUtil.equalsFlowModFlags(flags, f));
289                 assertEquals(expected,
290                              FlowCreatorUtil.equalsFlowModFlags(f, flags));
291             }
292
293             final boolean overlap = (bit == 0);
294             final boolean noByte = (bit == 1);
295             final boolean noPacket = (bit == 2);
296             final boolean reset = (bit == 3);
297             final boolean flowRem = (bit == 4);
298             FlowModFlags f =
299                 new FlowModFlags(overlap, noByte, noPacket, reset, flowRem);
300             assertTrue(FlowCreatorUtil.equalsFlowModFlags(flags, f));
301             assertTrue(FlowCreatorUtil.equalsFlowModFlags(f, flags));
302             assertTrue(FlowCreatorUtil.
303                        equalsFlowModFlags(f, new FlowModFlags(f)));
304
305             f = new FlowModFlags(!overlap, noByte, noPacket, reset, flowRem);
306             assertFalse(FlowCreatorUtil.equalsFlowModFlags(flags, f));
307             f = new FlowModFlags(overlap, !noByte, noPacket, reset, flowRem);
308             assertFalse(FlowCreatorUtil.equalsFlowModFlags(flags, f));
309             f = new FlowModFlags(overlap, noByte, !noPacket, reset, flowRem);
310             assertFalse(FlowCreatorUtil.equalsFlowModFlags(flags, f));
311             f = new FlowModFlags(overlap, noByte, noPacket, !reset, flowRem);
312             assertFalse(FlowCreatorUtil.equalsFlowModFlags(flags, f));
313             f = new FlowModFlags(overlap, noByte, noPacket, reset, !flowRem);
314             assertFalse(FlowCreatorUtil.equalsFlowModFlags(flags, f));
315
316             bit++;
317         }
318     }
319
320     /**
321      * Test method for
322      * {@link FlowCreatorUtil#equalsWithDefault(Object, Object, Object)}.
323      */
324     @Test
325     public void testEqualsWithDefault() {
326         // Boolean
327         for (final Boolean def: new Boolean[]{Boolean.TRUE, Boolean.FALSE}) {
328             assertTrue(FlowCreatorUtil.equalsWithDefault(null, null, def));
329             assertTrue(FlowCreatorUtil.equalsWithDefault(def, null, def));
330             assertTrue(FlowCreatorUtil.equalsWithDefault(null, def, def));
331
332             final Boolean inv = Boolean.valueOf(!def.booleanValue());
333             assertFalse(FlowCreatorUtil.equalsWithDefault(null, inv, def));
334             assertFalse(FlowCreatorUtil.equalsWithDefault(inv, null, def));
335         }
336
337         // Integer
338         final Integer[] integers = {
339             Integer.valueOf(-100),
340             Integer.valueOf(0),
341             Integer.valueOf(100),
342         };
343         for (final Integer def: integers) {
344             final Integer same = new Integer(def.intValue());
345             assertTrue(FlowCreatorUtil.equalsWithDefault(null, null, def));
346             assertTrue(FlowCreatorUtil.equalsWithDefault(same, null, def));
347             assertTrue(FlowCreatorUtil.equalsWithDefault(null, same, def));
348
349             final Integer diff = new Integer(def.intValue() +1);
350             assertFalse(FlowCreatorUtil.equalsWithDefault(null, diff, def));
351             assertFalse(FlowCreatorUtil.equalsWithDefault(diff, null, def));
352         }
353
354         // String
355         final String[] strings = {
356             "",
357             "test string 1",
358             "test string 2",
359         };
360         for (final String def: strings) {
361             final String same = new String(def);
362             assertTrue(FlowCreatorUtil.equalsWithDefault(null, null, def));
363             assertTrue(FlowCreatorUtil.equalsWithDefault(same, null, def));
364             assertTrue(FlowCreatorUtil.equalsWithDefault(null, same, def));
365
366             final String diff = def + "-1";
367             assertFalse(FlowCreatorUtil.equalsWithDefault(null, diff, def));
368             assertFalse(FlowCreatorUtil.equalsWithDefault(diff, null, def));
369         }
370     }
371
372     private void assertMatch (final Match match) {
373         assertTrue(match.getType().getClass().isInstance(OxmMatchType.class));
374     }
375
376     private void assertMatch (final MatchV10 matchV10) {
377         assertEquals(matchV10.getDlDst(), macAddress);
378         assertEquals(matchV10.getDlSrc(), macAddress);
379
380         assertTrue(matchV10.getNwSrcMask().shortValue() == 0);
381         assertTrue(matchV10.getNwDstMask().shortValue() == 0);
382
383         assertTrue(matchV10.getInPort().intValue() == 0);
384         assertTrue(matchV10.getDlVlan().intValue() == 0);
385         assertTrue(matchV10.getDlVlanPcp().shortValue() == 0);
386         assertTrue(matchV10.getDlType().intValue() == 0);
387
388         assertTrue(matchV10.getNwTos().shortValue() == 0);
389         assertTrue(matchV10.getNwProto().shortValue() == 0);
390
391         assertEquals(matchV10.getNwSrc(), ipv4Address);
392         assertEquals(matchV10.getNwDst(), ipv4Address);
393
394         assertTrue(matchV10.getTpSrc().intValue() == 0);
395         assertTrue(matchV10.getTpDst().intValue() == 0);
396     }
397
398     /**
399      * Verify that {@link FlowCreatorUtil#canModifyFlow(OriginalFlow, UpdatedFlow, Short)}
400      * returns expected value.
401      *
402      * @param expected
403      *     An expected return value.
404      * @param org
405      *     A original flow builder that contains original flow to be tested.
406      * @param upd
407      *     An updated flow builder that contains updated flow to be tested.
408      * @param version
409      *     OpenFlow protocol version.
410      */
411     private void canModifyFlowTest (final boolean expected, final OriginalFlowBuilder org,
412                                    final UpdatedFlowBuilder upd, final Short version) {
413         final boolean result = FlowCreatorUtil.
414             canModifyFlow(org.build(), upd.build(), version);
415         assertEquals(expected, result);
416     }
417
418     /**
419      * Create a flow match that specifies ethernet type.
420      *
421      * @param etherType  An ethernet type value.
422      * @return  A flow match that specifies the given ethernet type.
423      */
424     private org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match createMatch (final long etherType) {
425         final EthernetTypeBuilder ethType = new EthernetTypeBuilder().
426             setType(new EtherType(etherType));
427         final EthernetMatchBuilder ether = new EthernetMatchBuilder().
428             setEthernetType(ethType.build());
429         return new MatchBuilder().setEthernetMatch(ether.build()).build();
430     }
431 }