Exported package for classifier-definitions and action-definitions
[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
12
13 import java.util.ArrayList;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
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.definition.Parameter.Type;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.parameter.value.RangeValue;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatch;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatchBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;
38
39 import com.google.common.collect.ImmutableList;
40
41 /**
42  * Match against TCP or UDP, and source and/or destination ports
43  */
44 public class L4Classifier extends Classifier {
45
46     /**
47      * Source port parameter name
48      */
49     public static final String SRC_PORT_PARAM = "sourceport";
50     /**
51      * Source port range parameter name
52      */
53     public static final String SRC_PORT_RANGE_PARAM = "sourceport_range";
54     /**
55      * Destination port parameter name
56      */
57     public static final String DST_PORT_PARAM = "destport";
58     /**
59      * Destination port range parameter name
60      */
61     public static final String DST_PORT_RANGE_PARAM = "destport_range";
62
63     protected static final ClassifierDefinitionId ID = new ClassifierDefinitionId(
64             "4250ab32-e8b8-445a-aebb-e1bd2cdd291f");
65     /**
66      * Layer 4 classifier-definition
67      */
68     public static final ClassifierDefinition DEFINITION = new ClassifierDefinitionBuilder().setId(
69             new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f"))
70         .setParent(IpProtoClassifier.ID)
71         .setName(new ClassifierName("l4"))
72         .setDescription(new Description("Match on the port number of UDP or TCP traffic"))
73         .setParameter(
74                 ImmutableList.of(
75                         new ParameterBuilder().setName(new ParameterName(SRC_PORT_PARAM))
76                             .setDescription(new Description("The source port number to match against"))
77                             .setType(Type.Int)
78                             .build(),
79                         new ParameterBuilder().setName(new ParameterName(SRC_PORT_RANGE_PARAM))
80                             .setDescription(new Description("The source port range to match against"))
81                             .setType(Type.Range)
82                             .build(),
83                         new ParameterBuilder().setName(new ParameterName(DST_PORT_PARAM))
84                             .setDescription(new Description("The destination port number to match against"))
85                             .setType(Type.Int)
86                             .build(), new ParameterBuilder().setName(new ParameterName(DST_PORT_RANGE_PARAM))
87                             .setDescription(new Description("The destination port range to match against"))
88                             .setType(Type.Range)
89                             .build()))
90         .build();
91
92     protected L4Classifier(Classifier parent) {
93         super(parent);
94     }
95
96     @Override
97     public ClassifierDefinitionId getId() {
98         return ID;
99     }
100
101     @Override
102     public ClassifierDefinition getClassDef() {
103         return DEFINITION;
104     }
105
106     @Override
107     protected void checkPresenceOfRequiredParams(Map<String, ParameterValue> params) {
108         if (params.get(SRC_PORT_PARAM) != null && params.get(SRC_PORT_RANGE_PARAM) != null) {
109             throw new IllegalArgumentException("Classifier: {" + this.getClassDef().getName()
110                     + "}+. Illegal source port parameters: 'int' and 'range' values are mutually exclusive.");
111         }
112         if (params.get(DST_PORT_PARAM) != null && params.get(DST_PORT_RANGE_PARAM) != null) {
113             throw new IllegalArgumentException("Classifier: {" + this.getClassDef().getName()
114                     + "}+. Illegal destination port parameters: 'int' and 'range' values are mutually exclusive.");
115         }
116         if (params.get(SRC_PORT_PARAM) != null) {
117             if (params.get(SRC_PORT_PARAM).getIntValue() == null) {
118                 throw new IllegalArgumentException("Classifier: {" + this.getClassDef().getName()
119                         + "}+ Value of sourceport parameter is not present.");
120             }
121         }
122         if (params.get(SRC_PORT_RANGE_PARAM) != null) {
123             if (params.get(SRC_PORT_RANGE_PARAM) != null) {
124                 validateRangeValue(params.get(SRC_PORT_RANGE_PARAM).getRangeValue());
125             }
126         }
127
128         if (params.get(DST_PORT_PARAM) != null) {
129             if (params.get(DST_PORT_PARAM).getIntValue() == null) {
130                 throw new IllegalArgumentException("Classifier: {" + this.getClassDef().getName()
131                         + "}+ Value of destport parameter is not present.");
132             }
133         }
134         if (params.get(DST_PORT_RANGE_PARAM) != null) {
135             if (params.get(DST_PORT_RANGE_PARAM) != null) {
136                 validateRangeValue(params.get(DST_PORT_RANGE_PARAM).getRangeValue());
137             }
138         }
139     }
140
141     private void validateRangeValue(RangeValue rangeValueParam) {
142         if (rangeValueParam == null) {
143             throw new IllegalArgumentException("Classifier: {" + this.getClassDef().getName()
144                     + "}+ Range value is not present.");
145         }
146         final Long min = rangeValueParam.getMin();
147         final Long max = rangeValueParam.getMax();
148         if (min > max) {
149             throw new IllegalArgumentException("Range value mismatch. MIN {" + min + "} is greater than MAX {" + max
150                     + "}.");
151         }
152     }
153
154     @Override
155     public List<MatchBuilder> update(List<MatchBuilder> matches, Map<String, ParameterValue> params) {
156         Set<Long> sPorts = new HashSet<>();
157         Set<Long> dPorts = new HashSet<>();
158         if (params.get(SRC_PORT_PARAM) != null) {
159             sPorts.add(params.get(SRC_PORT_PARAM).getIntValue());
160         } else if (params.get(SRC_PORT_RANGE_PARAM) != null) {
161             sPorts.addAll(createSetFromRange(params.get(SRC_PORT_RANGE_PARAM).getRangeValue()));
162         }
163         if (params.get(DST_PORT_PARAM) != null) {
164             dPorts.add(params.get(DST_PORT_PARAM).getIntValue());
165         } else if (params.get(DST_PORT_RANGE_PARAM) != null) {
166             dPorts.addAll(createSetFromRange(params.get(DST_PORT_RANGE_PARAM).getRangeValue()));
167         }
168
169         List<MatchBuilder> newMatches = new ArrayList<>();
170         for (MatchBuilder matchBuilder : matches) {
171             Layer4Match l4Match = matchBuilder.getLayer4Match();
172             Set<? extends Layer4Match> l4Matches = null;
173             if (l4Match == null) {
174                 l4Match = resolveL4Match(params);
175             }
176             if (l4Match instanceof UdpMatch) {
177                 l4Matches = createUdpMatches((UdpMatch) l4Match, sPorts, dPorts);
178             } else if (l4Match instanceof TcpMatch) {
179                 l4Matches = createTcpMatches((TcpMatch) l4Match, sPorts, dPorts);
180             } else if (l4Match instanceof SctpMatch) {
181                 l4Matches = createSctpMatches((SctpMatch) l4Match, sPorts, dPorts);
182             }
183             for (Layer4Match newL4Match : l4Matches) {
184                 newMatches.add(new MatchBuilder(matchBuilder.build()).setLayer4Match(newL4Match));
185             }
186         }
187         return newMatches;
188     }
189
190     private Layer4Match resolveL4Match(Map<String, ParameterValue> params) {
191         Long ipProto = IpProtoClassifier.getIpProtoValue(params);
192         if (ipProto == null) {
193             throw new IllegalArgumentException("Classifier-instance " + this.getClassDef().getName()
194                     + ": L4 protocol is null.");
195         }
196         if (IpProtoClassifier.UDP_VALUE.equals(ipProto)) {
197             return new UdpMatchBuilder().build();
198         } else if (IpProtoClassifier.TCP_VALUE.equals(ipProto)) {
199             return new TcpMatchBuilder().build();
200         } else if (IpProtoClassifier.SCTP_VALUE.equals(ipProto)) {
201             return new SctpMatchBuilder().build();
202         }
203         throw new IllegalArgumentException("Unsupported L4 protocol.");
204     }
205
206     private Set<Long> createSetFromRange(RangeValue rangeValueParam) {
207         Set<Long> res = new HashSet<>();
208         if (rangeValueParam != null) {
209             final Long min = rangeValueParam.getMin();
210             final Long max = rangeValueParam.getMax();
211             for (long val = min; val <= max; val++) {
212                 res.add(val);
213             }
214         }
215         return res;
216     }
217
218     private Set<UdpMatch> createUdpMatches(UdpMatch udpMatch, Set<Long> sPorts, Set<Long> dPorts) {
219         Set<UdpMatch> udpMatches = new HashSet<>();
220         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
221             for (Long srcPort : sPorts) {
222                 equalOrNotSetValidation(udpMatch.getUdpSourcePort(), srcPort.longValue());
223                 udpMatches.add(new UdpMatchBuilder(udpMatch).setUdpSourcePort(new PortNumber(srcPort.intValue())).build());
224             }
225         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
226             for (Long dstPort : dPorts) {
227                 equalOrNotSetValidation(udpMatch.getUdpDestinationPort(), dstPort.longValue());
228                 udpMatches.add(new UdpMatchBuilder(udpMatch).setUdpDestinationPort(new PortNumber(dstPort.intValue()))
229                     .build());
230             }
231         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
232             for (Long srcPort : sPorts) {
233                 for (Long dstPort : dPorts) {
234                     equalOrNotSetValidation(udpMatch.getUdpSourcePort(), srcPort.longValue());
235                     equalOrNotSetValidation(udpMatch.getUdpDestinationPort(), dstPort.longValue());
236                     udpMatches.add(new UdpMatchBuilder(udpMatch).setUdpSourcePort(new PortNumber(srcPort.intValue()))
237                         .setUdpDestinationPort(new PortNumber(dstPort.intValue()))
238                         .build());
239                 }
240             }
241         }
242         return udpMatches;
243     }
244
245     private Set<TcpMatch> createTcpMatches(TcpMatch tcpMatch, Set<Long> sPorts, Set<Long> dPorts) {
246         Set<TcpMatch> tcpMatches = new HashSet<>();
247         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
248             for (Long srcPort : sPorts) {
249                 equalOrNotSetValidation(tcpMatch.getTcpSourcePort(), srcPort.longValue());
250                 tcpMatches.add(new TcpMatchBuilder(tcpMatch).setTcpSourcePort(new PortNumber(srcPort.intValue())).build());
251             }
252         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
253             for (Long dstPort : dPorts) {
254                 equalOrNotSetValidation(tcpMatch.getTcpDestinationPort(), dstPort.longValue());
255                 tcpMatches.add(new TcpMatchBuilder(tcpMatch).setTcpDestinationPort(new PortNumber(dstPort.intValue()))
256                     .build());
257             }
258         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
259             for (Long srcPort : sPorts) {
260                 for (Long dstPort : dPorts) {
261                     equalOrNotSetValidation(tcpMatch.getTcpSourcePort(), srcPort.longValue());
262                     equalOrNotSetValidation(tcpMatch.getTcpDestinationPort(), dstPort.longValue());
263                     tcpMatches.add(new TcpMatchBuilder(tcpMatch).setTcpSourcePort(new PortNumber(srcPort.intValue()))
264                         .setTcpDestinationPort(new PortNumber(dstPort.intValue()))
265                         .build());
266                 }
267             }
268         }
269         return tcpMatches;
270     }
271
272     private Set<SctpMatch> createSctpMatches(SctpMatch sctpMatch, Set<Long> sPorts, Set<Long> dPorts) {
273         Set<SctpMatch> sctpMatches = new HashSet<>();
274         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
275             for (Long srcPort : sPorts) {
276                 equalOrNotSetValidation(sctpMatch.getSctpSourcePort(), srcPort.longValue());
277                 sctpMatches.add(new SctpMatchBuilder(sctpMatch).setSctpSourcePort(new PortNumber(srcPort.intValue()))
278                     .build());
279             }
280         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
281             for (Long dstPort : dPorts) {
282                 equalOrNotSetValidation(sctpMatch.getSctpDestinationPort(), dstPort.longValue());
283                 sctpMatches.add(new SctpMatchBuilder(sctpMatch).setSctpDestinationPort(new PortNumber(dstPort.intValue()))
284                     .build());
285             }
286         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
287             for (Long srcPort : sPorts) {
288                 for (Long dstPort : dPorts) {
289                     equalOrNotSetValidation(sctpMatch.getSctpSourcePort(), srcPort.longValue());
290                     equalOrNotSetValidation(sctpMatch.getSctpDestinationPort(), dstPort.longValue());
291                     sctpMatches.add(new SctpMatchBuilder(sctpMatch).setSctpSourcePort(new PortNumber(srcPort.intValue()))
292                         .setSctpDestinationPort(new PortNumber(dstPort.intValue()))
293                         .build());
294                 }
295             }
296         }
297         return sctpMatches;
298     }
299
300     private void equalOrNotSetValidation(PortNumber portInMatch, long paramValue) {
301         if (portInMatch != null) {
302             if (paramValue != portInMatch.getValue().longValue()) {
303                 throw new IllegalArgumentException("Classification conflict at " + this.getClassDef().getName()
304                         + ": Trying to override port value: " + portInMatch.getValue().longValue() + " by value "
305                         + paramValue);
306             }
307         }
308     }
309
310     @Override
311     public void checkPrereqs(List<MatchBuilder> matches) {
312         for (MatchBuilder match : matches) {
313             Long proto = null;
314             try {
315                 proto = Long.valueOf(match.getIpMatch().getIpProtocol().longValue());
316             } catch (NullPointerException e) {
317                 throw new IllegalArgumentException("Ip proto match is missing.");
318             }
319             if (!IpProtoClassifier.TCP_VALUE.equals(proto) && !IpProtoClassifier.UDP_VALUE.equals(proto)
320                     && !IpProtoClassifier.SCTP_VALUE.equals(proto)) {
321                 throw new IllegalArgumentException("Unsupported proto value.\n" + "Classifier: "
322                         + this.getClass().getName() + ", proto set: " + proto);
323             }
324         }
325     }
326 }