Bug 5540 - FlowConvertor, FlowStatsResponseConvertor, FlowInstructionResponseConvertor
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / util / FlowCreatorUtil.java
1 /*
2  * Copyright (c) 2013, 2015 IBM Corporation 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
9 package org.opendaylight.openflowplugin.openflow.md.util;
10
11 import java.math.BigInteger;
12 import java.util.Objects;
13 import org.opendaylight.openflowplugin.api.OFConstants;
14 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
16 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.FlowConvertor;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowWildcardsV10;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.OxmMatchType;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.Match;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.MatchBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.v10.grouping.MatchV10;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.v10.grouping.MatchV10Builder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.aggregate._case.MultipartRequestAggregateBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.flow._case.MultipartRequestFlowBuilder;
29
30 public final class FlowCreatorUtil {
31     /**
32      * Default FLOW_MOD flags.
33      */
34     public static final FlowModFlags  DEFAULT_FLOW_MOD_FLAGS =
35         new FlowModFlags(FlowConvertor.DEFAULT_OFPFF_CHECK_OVERLAP,
36                          FlowConvertor.DEFAULT_OFPFF_NO_BYT_COUNTS,
37                          FlowConvertor.DEFAULT_OFPFF_NO_PKT_COUNTS,
38                          FlowConvertor.DEFAULT_OFPFF_RESET_COUNTS,
39                          FlowConvertor.DEFAULT_OFPFF_FLOW_REM);
40
41     private FlowCreatorUtil() {
42         throw new AssertionError("FlowCreatorUtil is not expected to be instantiated.");
43     }
44
45     public static void setWildcardedFlowMatch(short version, MultipartRequestFlowBuilder flowBuilder) {
46         if (version == OFConstants.OFP_VERSION_1_0) {
47             flowBuilder.setMatchV10(createWildcardedMatchV10());
48         }
49         if (version == OFConstants.OFP_VERSION_1_3) {
50             flowBuilder.setMatch(createWildcardedMatch());
51         }
52     }
53
54     public static void setWildcardedFlowMatch(short version, MultipartRequestAggregateBuilder aggregateBuilder) {
55         if (version == OFConstants.OFP_VERSION_1_0) {
56             aggregateBuilder.setMatchV10(createWildcardedMatchV10());
57         }
58         if (version == OFConstants.OFP_VERSION_1_3) {
59             aggregateBuilder.setMatch(createWildcardedMatch());
60         }
61     }
62
63     /**
64      * Method creates openflow 1.0 format match, that can match all the flow entries.
65      *
66      * @return V10 Match object
67      */
68     public static MatchV10 createWildcardedMatchV10() {
69         MatchV10Builder builder = new MatchV10Builder();
70         builder.setWildcards(new FlowWildcardsV10(true, true, true, true,
71                 true, true, true, true, true, true));
72         builder.setNwSrcMask((short) 0);
73         builder.setNwDstMask((short) 0);
74         builder.setInPort(0);
75         builder.setDlSrc(new MacAddress("00:00:00:00:00:00"));
76         builder.setDlDst(new MacAddress("00:00:00:00:00:00"));
77         builder.setDlVlan(0);
78         builder.setDlVlanPcp((short) 0);
79         builder.setDlType(0);
80         builder.setNwTos((short) 0);
81         builder.setNwProto((short) 0);
82         builder.setNwSrc(new Ipv4Address("0.0.0.0"));
83         builder.setNwDst(new Ipv4Address("0.0.0.0"));
84         builder.setTpSrc(0);
85         builder.setTpDst(0);
86         return builder.build();
87     }
88
89     public static Match createWildcardedMatch() {
90         return new MatchBuilder().setType(OxmMatchType.class).build();
91     }
92
93     /**
94      * Determine whether a flow entry can be modified or not.
95      *
96      * @param original  An original flow entry.
97      * @param updated   An updated flow entry.
98      * @param version   Protocol version.
99      * @return  {@code true} only if a flow entry can be modified.
100      */
101     public static boolean canModifyFlow(OriginalFlow original,
102                                         UpdatedFlow updated, Short version) {
103         // FLOW_MOD does not change match, priority, idle_timeout, hard_timeout,
104         // flags, and cookie.
105         if (!Objects.equals(original.getMatch(), updated.getMatch()) ||
106             !equalsWithDefault(original.getPriority(), updated.getPriority(),
107                                FlowConvertor.DEFAULT_PRIORITY) ||
108             !equalsWithDefault(original.getIdleTimeout(),
109                                updated.getIdleTimeout(),
110                                FlowConvertor.DEFAULT_IDLE_TIMEOUT) ||
111             !equalsWithDefault(original.getHardTimeout(),
112                                updated.getHardTimeout(),
113                                FlowConvertor.DEFAULT_HARD_TIMEOUT) ||
114             !equalsFlowModFlags(original.getFlags(), updated.getFlags())) {
115             return false;
116         }
117
118         if (!Boolean.TRUE.equals(updated.isStrict()) &&
119             version != null &&
120             version.shortValue() != OFConstants.OFP_VERSION_1_0) {
121             FlowCookie cookieMask = updated.getCookieMask();
122             if (cookieMask != null) {
123                 BigInteger mask = cookieMask.getValue();
124                 if (mask != null && !mask.equals(BigInteger.ZERO)) {
125                     // Allow FLOW_MOD with filtering by cookie.
126                     return true;
127                 }
128             }
129         }
130
131         FlowCookie oc = original.getCookie();
132         FlowCookie uc = updated.getCookie();
133         BigInteger orgCookie;
134         BigInteger updCookie;
135         if (oc == null) {
136             if (uc == null) {
137                 return true;
138             }
139
140             orgCookie = OFConstants.DEFAULT_COOKIE;
141             updCookie = uc.getValue();
142         } else {
143             orgCookie = oc.getValue();
144             updCookie = (uc == null)
145                 ? OFConstants.DEFAULT_COOKIE : uc.getValue();
146         }
147
148         return equalsWithDefault(orgCookie, updCookie,
149                                  OFConstants.DEFAULT_COOKIE);
150     }
151
152     /**
153      * Return {@code true} only if given two FLOW_MOD flags are identical.
154      *
155      * @param flags1 A value to be compared.
156      * @param flags2 A value to be compared.
157      * @return
158      *   {@code true} only if {@code flags1} and {@code flags2} are identical.
159      */
160     public static boolean equalsFlowModFlags(FlowModFlags flags1,
161                                              FlowModFlags flags2) {
162         FlowModFlags f1;
163         FlowModFlags f2;
164         if (flags1 == null) {
165             if (flags2 == null) {
166                 return true;
167             }
168
169             f1 = DEFAULT_FLOW_MOD_FLAGS;
170             f2 = flags2;
171         } else {
172             f1 = flags1;
173             f2 = (flags2 == null) ? DEFAULT_FLOW_MOD_FLAGS : flags2;
174         }
175
176         return equalsWithDefault(f1.isCHECKOVERLAP(), f2.isCHECKOVERLAP(),
177                                  Boolean.FALSE) &&
178             equalsWithDefault(f1.isNOBYTCOUNTS(), f2.isNOBYTCOUNTS(),
179                               Boolean.FALSE) &&
180             equalsWithDefault(f1.isNOPKTCOUNTS(), f2.isNOPKTCOUNTS(),
181                               Boolean.FALSE) &&
182             equalsWithDefault(f1.isRESETCOUNTS(), f2.isRESETCOUNTS(),
183                               Boolean.FALSE) &&
184             equalsWithDefault(f1.isSENDFLOWREM(), f2.isSENDFLOWREM(),
185                               Boolean.FALSE);
186     }
187
188     /**
189      * Return {@code true} only if given two values are identical.
190      *
191      * @param value1 A value to be compared.
192      * @param value2 A value to be compared.
193      * @param def
194      *    Default value. This value is used if {@code null} is passed to
195      *    {@code value1} or {@code value2}.
196      * @param <T> Type of values.
197      * @return
198      *   {@code true} only if {@code value1} and {@code value2} are identical.
199      */
200     public static <T> boolean equalsWithDefault(T value1, T value2, T def) {
201         if (value1 == null) {
202             return value2 == null || value2.equals(def);
203         } else if (value2 == null) {
204             return value1.equals(def);
205         }
206
207         return value1.equals(value2);
208     }
209 }