GBP ofoverlay.sf test improvements
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / sf / L4Classifier.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
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
10
11 import java.util.ArrayList;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 import com.google.common.collect.ImmutableList;
18
19 import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
20 import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.parameter.value.RangeValue;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.parameters.type.parameter.type.IntBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.has.parameters.type.parameter.type.RangeBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValues;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValuesBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.supported._int.value.fields.SupportedIntValueInRange;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.supported._int.value.fields.SupportedIntValueInRangeBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.supported.range.value.fields.SupportedRangeValue;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.supported.range.value.fields.SupportedRangeValueBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatch;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatchBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;
43
44 /**
45  * Match against TCP or UDP, and source and/or destination ports
46  */
47 public class L4Classifier extends Classifier {
48
49     protected L4Classifier(Classifier parent) {
50         super(parent);
51     }
52
53     @Override
54     public ClassifierDefinitionId getId() {
55         return L4ClassifierDefinition.ID;
56     }
57
58     @Override
59     public ClassifierDefinition getClassifierDefinition() {
60         return L4ClassifierDefinition.DEFINITION;
61     }
62
63     @Override
64     public List<SupportedParameterValues> getSupportedParameterValues() {
65         List<SupportedIntValueInRange> allPossiblePortsIntInRange =
66                 ImmutableList.of(new SupportedIntValueInRangeBuilder().setMin(1L).setMax(65535L).build());
67         List<SupportedRangeValue> allPossiblePortsRange =
68                 ImmutableList.of(new SupportedRangeValueBuilder().setMin(1L).setMax(65535L).build());
69
70         SupportedParameterValues srcPorts = new SupportedParameterValuesBuilder()
71             .setParameterName(new ParameterName(L4ClassifierDefinition.SRC_PORT_PARAM))
72             .setParameterType(new IntBuilder().setSupportedIntValueInRange(allPossiblePortsIntInRange).build())
73             .build();
74         SupportedParameterValues dstPorts = new SupportedParameterValuesBuilder()
75             .setParameterName(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM))
76             .setParameterType(new IntBuilder().setSupportedIntValueInRange(allPossiblePortsIntInRange).build())
77             .build();
78
79         SupportedParameterValues srcPortsRange = new SupportedParameterValuesBuilder()
80             .setParameterName(new ParameterName(L4ClassifierDefinition.SRC_PORT_RANGE_PARAM))
81             .setParameterType(new RangeBuilder().setSupportedRangeValue(allPossiblePortsRange).build())
82             .build();
83         SupportedParameterValues dstPortsRange = new SupportedParameterValuesBuilder()
84             .setParameterName(new ParameterName(L4ClassifierDefinition.DST_PORT_RANGE_PARAM))
85             .setParameterType(new RangeBuilder().setSupportedRangeValue(allPossiblePortsRange).build())
86             .build();
87
88         return ImmutableList.of(srcPorts, dstPorts, srcPortsRange, dstPortsRange);
89     }
90
91     @Override
92     protected void checkPresenceOfRequiredParams(Map<String, ParameterValue> params) {
93         validatePortParam(params, L4ClassifierDefinition.SRC_PORT_PARAM, L4ClassifierDefinition.SRC_PORT_RANGE_PARAM);
94         validatePortParam(params, L4ClassifierDefinition.DST_PORT_PARAM, L4ClassifierDefinition.DST_PORT_RANGE_PARAM);
95         validateRange(params, L4ClassifierDefinition.SRC_PORT_RANGE_PARAM);
96         validateRange(params, L4ClassifierDefinition.DST_PORT_RANGE_PARAM);
97     }
98
99     private void validatePortParam(Map<String, ParameterValue> params, String portParam, String portRangeParam) {
100         if (params.get(portParam) != null) {
101             StringBuilder paramLog = new StringBuilder();
102             if (params.get(portParam).getIntValue() == null) {
103                 paramLog.append("Value of ").append(portParam).append(" parameter " + MSG_NOT_SPECIFIED);
104                 throw new IllegalArgumentException(paramLog.toString());
105             }
106             if (params.get(portRangeParam) != null) {
107                 paramLog.append("Source port parameters ")
108                     .append(portParam)
109                     .append(" and ")
110                     .append(portRangeParam)
111                     .append(" are " + MSG_MUTUALLY_EXCLUSIVE);
112                 throw new IllegalArgumentException(paramLog.toString());
113             }
114         }
115     }
116
117     private void validateRange(Map<String, ParameterValue> params, String portRangeParam) {
118         if (params.get(portRangeParam) != null) {
119             validateRangeValue(params.get(portRangeParam).getRangeValue());
120         }
121     }
122
123     private void validateRangeValue(RangeValue rangeValueParam) {
124         if (rangeValueParam == null) {
125             throw new IllegalArgumentException(
126                     "Range parameter is specified but value is " + Classifier.MSG_NOT_PRESENT);
127         }
128         final Long min = rangeValueParam.getMin();
129         final Long max = rangeValueParam.getMax();
130         if (min > max) {
131             throw new IllegalArgumentException(
132                     MSG_RANGE_VALUE_MISMATCH + " MIN " + min + " is greater than MAX " + max + ".");
133         }
134     }
135
136     @Override
137     public List<MatchBuilder> update(List<MatchBuilder> matches, Map<String, ParameterValue> params) {
138         Set<Long> sPorts = new HashSet<>();
139         Set<Long> dPorts = new HashSet<>();
140         addToPortSet(params, L4ClassifierDefinition.SRC_PORT_PARAM, L4ClassifierDefinition.SRC_PORT_RANGE_PARAM,
141                 sPorts);
142         addToPortSet(params, L4ClassifierDefinition.DST_PORT_PARAM, L4ClassifierDefinition.DST_PORT_RANGE_PARAM,
143                 dPorts);
144         List<MatchBuilder> newMatches = new ArrayList<>();
145         for (MatchBuilder matchBuilder : matches) {
146             Layer4Match l4Match = matchBuilder.getLayer4Match();
147             Set<? extends Layer4Match> l4Matches = null;
148             if (l4Match == null) {
149                 l4Match = resolveL4Match(params);
150             }
151             l4Matches = createL4Matches(l4Match, sPorts, dPorts);
152             for (Layer4Match newL4Match : l4Matches) {
153                 newMatches.add(new MatchBuilder(matchBuilder.build()).setLayer4Match(newL4Match));
154             }
155         }
156         return newMatches;
157     }
158
159     private void addToPortSet(Map<String, ParameterValue> params, String portParam, String portRangeParam,
160             Set<Long> portSet) {
161         if (params.get(portParam) != null) {
162             portSet.add(params.get(portParam).getIntValue());
163         } else if (params.get(portRangeParam) != null) {
164             portSet.addAll(createSetFromRange(params.get(portRangeParam).getRangeValue()));
165         }
166     }
167
168     private Layer4Match resolveL4Match(Map<String, ParameterValue> params) {
169         Long ipProto = IpProtoClassifier.getIpProtoValue(params);
170         if (ipProto == null) {
171             throw new IllegalArgumentException("Parameter " + IpProtoClassifierDefinition.PROTO_PARAM + " is missing.");
172         }
173         if (IpProtoClassifierDefinition.UDP_VALUE.equals(ipProto)) {
174             return new UdpMatchBuilder().build();
175         } else if (IpProtoClassifierDefinition.TCP_VALUE.equals(ipProto)) {
176             return new TcpMatchBuilder().build();
177         } else if (IpProtoClassifierDefinition.SCTP_VALUE.equals(ipProto)) {
178             return new SctpMatchBuilder().build();
179         }
180         throw new IllegalArgumentException("Parameter " + IpProtoClassifierDefinition.PROTO_PARAM + ": value " + ipProto
181                 + " is " + Classifier.MSG_NOT_SUPPORTED);
182     }
183
184     private Set<Long> createSetFromRange(RangeValue rangeValueParam) {
185         Set<Long> res = new HashSet<>();
186         if (rangeValueParam != null) {
187             final Long min = rangeValueParam.getMin();
188             final Long max = rangeValueParam.getMax();
189             for (long val = min; val <= max; val++) {
190                 res.add(val);
191             }
192         }
193         return res;
194     }
195
196     private Set<? extends Layer4Match> createL4Matches(Layer4Match l4Match, Set<Long> sPorts, Set<Long> dPorts) {
197         Set<? extends Layer4Match> l4Matches = null;
198         if (l4Match instanceof UdpMatch) {
199             l4Matches = createUdpMatches((UdpMatch) l4Match, sPorts, dPorts);
200         } else if (l4Match instanceof TcpMatch) {
201             l4Matches = createTcpMatches((TcpMatch) l4Match, sPorts, dPorts);
202         } else if (l4Match instanceof SctpMatch) {
203             l4Matches = createSctpMatches((SctpMatch) l4Match, sPorts, dPorts);
204         }
205         return l4Matches;
206     }
207
208     private Set<UdpMatch> createUdpMatches(UdpMatch udpMatch, Set<Long> sPorts, Set<Long> dPorts) {
209         Set<UdpMatch> udpMatches = new HashSet<>();
210         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
211             for (Long srcPort : sPorts) {
212                 equalOrNotSetValidation(udpMatch.getUdpSourcePort(), srcPort.longValue());
213                 udpMatches
214                     .add(new UdpMatchBuilder(udpMatch).setUdpSourcePort(new PortNumber(srcPort.intValue())).build());
215             }
216         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
217             for (Long dstPort : dPorts) {
218                 equalOrNotSetValidation(udpMatch.getUdpDestinationPort(), dstPort.longValue());
219                 udpMatches.add(new UdpMatchBuilder(udpMatch).setUdpDestinationPort(new PortNumber(dstPort.intValue()))
220                     .build());
221             }
222         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
223             for (Long srcPort : sPorts) {
224                 for (Long dstPort : dPorts) {
225                     equalOrNotSetValidation(udpMatch.getUdpSourcePort(), srcPort.longValue());
226                     equalOrNotSetValidation(udpMatch.getUdpDestinationPort(), dstPort.longValue());
227                     udpMatches.add(new UdpMatchBuilder(udpMatch).setUdpSourcePort(new PortNumber(srcPort.intValue()))
228                         .setUdpDestinationPort(new PortNumber(dstPort.intValue()))
229                         .build());
230                 }
231             }
232         }
233         return udpMatches;
234     }
235
236     private Set<TcpMatch> createTcpMatches(TcpMatch tcpMatch, Set<Long> sPorts, Set<Long> dPorts) {
237         Set<TcpMatch> tcpMatches = new HashSet<>();
238         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
239             for (Long srcPort : sPorts) {
240                 equalOrNotSetValidation(tcpMatch.getTcpSourcePort(), srcPort.longValue());
241                 tcpMatches
242                     .add(new TcpMatchBuilder(tcpMatch).setTcpSourcePort(new PortNumber(srcPort.intValue())).build());
243             }
244         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
245             for (Long dstPort : dPorts) {
246                 equalOrNotSetValidation(tcpMatch.getTcpDestinationPort(), dstPort.longValue());
247                 tcpMatches.add(new TcpMatchBuilder(tcpMatch).setTcpDestinationPort(new PortNumber(dstPort.intValue()))
248                     .build());
249             }
250         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
251             for (Long srcPort : sPorts) {
252                 for (Long dstPort : dPorts) {
253                     equalOrNotSetValidation(tcpMatch.getTcpSourcePort(), srcPort.longValue());
254                     equalOrNotSetValidation(tcpMatch.getTcpDestinationPort(), dstPort.longValue());
255                     tcpMatches.add(new TcpMatchBuilder(tcpMatch).setTcpSourcePort(new PortNumber(srcPort.intValue()))
256                         .setTcpDestinationPort(new PortNumber(dstPort.intValue()))
257                         .build());
258                 }
259             }
260         }
261         return tcpMatches;
262     }
263
264     private Set<SctpMatch> createSctpMatches(SctpMatch sctpMatch, Set<Long> sPorts, Set<Long> dPorts) {
265         Set<SctpMatch> sctpMatches = new HashSet<>();
266         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
267             for (Long srcPort : sPorts) {
268                 equalOrNotSetValidation(sctpMatch.getSctpSourcePort(), srcPort.longValue());
269                 sctpMatches
270                     .add(new SctpMatchBuilder(sctpMatch).setSctpSourcePort(new PortNumber(srcPort.intValue())).build());
271             }
272         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
273             for (Long dstPort : dPorts) {
274                 equalOrNotSetValidation(sctpMatch.getSctpDestinationPort(), dstPort.longValue());
275                 sctpMatches.add(new SctpMatchBuilder(sctpMatch)
276                     .setSctpDestinationPort(new PortNumber(dstPort.intValue())).build());
277             }
278         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
279             for (Long srcPort : sPorts) {
280                 for (Long dstPort : dPorts) {
281                     equalOrNotSetValidation(sctpMatch.getSctpSourcePort(), srcPort.longValue());
282                     equalOrNotSetValidation(sctpMatch.getSctpDestinationPort(), dstPort.longValue());
283                     sctpMatches
284                         .add(new SctpMatchBuilder(sctpMatch).setSctpSourcePort(new PortNumber(srcPort.intValue()))
285                             .setSctpDestinationPort(new PortNumber(dstPort.intValue()))
286                             .build());
287                 }
288             }
289         }
290         return sctpMatches;
291     }
292
293     private void equalOrNotSetValidation(PortNumber portInMatch, long paramValue) {
294         if (portInMatch != null) {
295             if (paramValue != portInMatch.getValue().longValue()) {
296                 throw new IllegalArgumentException(Classifier.MSG_CLASSIFICATION_CONFLICT_DETECTED + " for port values "
297                         + portInMatch.getValue().longValue() + " and " + paramValue + ". It is not allowed "
298                         + "to assign different values to the same parameter among all the classifiers within one rule.");
299             }
300         }
301     }
302
303     @Override
304     public void checkPrereqs(List<MatchBuilder> matches) {
305         for (MatchBuilder match : matches) {
306             Long proto = null;
307             try {
308                 proto = Long.valueOf(match.getIpMatch().getIpProtocol().longValue());
309             } catch (NullPointerException e) {
310                 throw new IllegalArgumentException(
311                         "Parameter " + IpProtoClassifierDefinition.PROTO_PARAM + " " + MSG_IS_MISSING);
312             }
313             if (!IpProtoClassifierDefinition.TCP_VALUE.equals(proto)
314                     && !IpProtoClassifierDefinition.UDP_VALUE.equals(proto)
315                     && !IpProtoClassifierDefinition.SCTP_VALUE.equals(proto)) {
316                 throw new IllegalArgumentException("Value of parameter " + IpProtoClassifierDefinition.PROTO_PARAM
317                         + " is " + Classifier.MSG_NOT_SUPPORTED);
318             }
319         }
320     }
321 }