Move definitions of classifiers and actions to
[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 org.opendaylight.groupbasedpolicy.sf.classifiers.IpProtoClassifierDefinition;
18 import org.opendaylight.groupbasedpolicy.sf.classifiers.L4ClassifierDefinition;
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.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.parameter.value.RangeValue;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatch;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatchBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;
32
33 /**
34  * Match against TCP or UDP, and source and/or destination ports
35  */
36 public class L4Classifier extends Classifier {
37
38     protected L4Classifier(Classifier parent) {
39         super(parent);
40     }
41
42     @Override
43     public ClassifierDefinitionId getId() {
44         return L4ClassifierDefinition.ID;
45     }
46
47     @Override
48     public ClassifierDefinition getClassDef() {
49         return L4ClassifierDefinition.DEFINITION;
50     }
51
52     @Override
53     protected void checkPresenceOfRequiredParams(Map<String, ParameterValue> params) {
54         validatePortParam(params, L4ClassifierDefinition.SRC_PORT_PARAM, L4ClassifierDefinition.SRC_PORT_RANGE_PARAM);
55         validatePortParam(params, L4ClassifierDefinition.DST_PORT_PARAM, L4ClassifierDefinition.DST_PORT_RANGE_PARAM);
56         validateRange(params, L4ClassifierDefinition.SRC_PORT_RANGE_PARAM);
57         validateRange(params, L4ClassifierDefinition.DST_PORT_RANGE_PARAM);
58     }
59
60     private void validatePortParam(Map<String, ParameterValue> params, String portParam, String portRangeParam) {
61         if (params.get(portParam) != null) {
62             StringBuilder paramLog = new StringBuilder();
63             if (params.get(portParam).getIntValue() == null) {
64                 paramLog.append("Value of ")
65                     .append(portParam)
66                     .append(" parameter is not specified.");
67                 throw new IllegalArgumentException(paramLog.toString());
68             }
69             if(params.get(portRangeParam) != null) {
70                 paramLog.append("Source port parameters ")
71                     .append(portParam)
72                     .append(" and ")
73                     .append(portRangeParam)
74                     .append(" are mutually exclusive.");
75                 throw new IllegalArgumentException(paramLog.toString());
76             }
77         }
78     }
79
80     private void validateRange(Map<String, ParameterValue> params, String portRangeParam) {
81         if (params.get(portRangeParam) != null) {
82             validateRangeValue(params.get(portRangeParam).getRangeValue());
83         }
84     }
85
86     private void validateRangeValue(RangeValue rangeValueParam) {
87         if (rangeValueParam == null) {
88             throw new IllegalArgumentException("Range parameter is specifiet but value is not present.");
89         }
90         final Long min = rangeValueParam.getMin();
91         final Long max = rangeValueParam.getMax();
92         if (min > max) {
93             throw new IllegalArgumentException("Range value mismatch. " + min + " is greater than MAX " + max + ".");
94         }
95     }
96
97     @Override
98     public List<MatchBuilder> update(List<MatchBuilder> matches, Map<String, ParameterValue> params) {
99         Set<Long> sPorts = new HashSet<>();
100         Set<Long> dPorts = new HashSet<>();
101         addToPortSet(params, L4ClassifierDefinition.SRC_PORT_PARAM, L4ClassifierDefinition.SRC_PORT_RANGE_PARAM, sPorts);
102         addToPortSet(params, L4ClassifierDefinition.DST_PORT_PARAM, L4ClassifierDefinition.DST_PORT_RANGE_PARAM, dPorts);
103         List<MatchBuilder> newMatches = new ArrayList<>();
104         for (MatchBuilder matchBuilder : matches) {
105             Layer4Match l4Match = matchBuilder.getLayer4Match();
106             Set<? extends Layer4Match> l4Matches = null;
107             if (l4Match == null) {
108                 l4Match = resolveL4Match(params);
109             }
110             l4Matches = createL4Matches(l4Match, sPorts, dPorts);
111             for (Layer4Match newL4Match : l4Matches) {
112                 newMatches.add(new MatchBuilder(matchBuilder.build()).setLayer4Match(newL4Match));
113             }
114         }
115         return newMatches;
116     }
117
118     private void addToPortSet(Map<String, ParameterValue> params, String portParam, String portRangeParam, Set<Long> portSet) {
119         if (params.get(portParam) != null) {
120             portSet.add(params.get(portParam).getIntValue());
121         } else if (params.get(portRangeParam) != null) {
122             portSet.addAll(createSetFromRange(params.get(portRangeParam).getRangeValue()));
123         }
124     }
125
126     private Layer4Match resolveL4Match(Map<String, ParameterValue> params) {
127         Long ipProto = IpProtoClassifier.getIpProtoValue(params);
128         if (ipProto == null) {
129             throw new IllegalArgumentException("Parameter " + IpProtoClassifierDefinition.PROTO_PARAM + " is missing.");
130         }
131         if (IpProtoClassifierDefinition.UDP_VALUE.equals(ipProto)) {
132             return new UdpMatchBuilder().build();
133         } else if (IpProtoClassifierDefinition.TCP_VALUE.equals(ipProto)) {
134             return new TcpMatchBuilder().build();
135         } else if (IpProtoClassifierDefinition.SCTP_VALUE.equals(ipProto)) {
136             return new SctpMatchBuilder().build();
137         }
138         throw new IllegalArgumentException("Parameter " + IpProtoClassifierDefinition.PROTO_PARAM + ": value " + ipProto
139                 + " is not supported.");
140     }
141
142     private Set<Long> createSetFromRange(RangeValue rangeValueParam) {
143         Set<Long> res = new HashSet<>();
144         if (rangeValueParam != null) {
145             final Long min = rangeValueParam.getMin();
146             final Long max = rangeValueParam.getMax();
147             for (long val = min; val <= max; val++) {
148                 res.add(val);
149             }
150         }
151         return res;
152     }
153
154     private Set<? extends Layer4Match> createL4Matches(Layer4Match l4Match, Set<Long> sPorts, Set<Long> dPorts) {
155         Set<? extends Layer4Match> l4Matches = null;
156         if (l4Match instanceof UdpMatch) {
157             l4Matches = createUdpMatches((UdpMatch) l4Match, sPorts, dPorts);
158         } else if (l4Match instanceof TcpMatch) {
159             l4Matches = createTcpMatches((TcpMatch) l4Match, sPorts, dPorts);
160         } else if (l4Match instanceof SctpMatch) {
161             l4Matches = createSctpMatches((SctpMatch) l4Match, sPorts, dPorts);
162         }
163         return l4Matches;
164     }
165
166     private Set<UdpMatch> createUdpMatches(UdpMatch udpMatch, Set<Long> sPorts, Set<Long> dPorts) {
167         Set<UdpMatch> udpMatches = new HashSet<>();
168         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
169             for (Long srcPort : sPorts) {
170                 equalOrNotSetValidation(udpMatch.getUdpSourcePort(), srcPort.longValue());
171                 udpMatches.add(new UdpMatchBuilder(udpMatch).setUdpSourcePort(new PortNumber(srcPort.intValue())).build());
172             }
173         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
174             for (Long dstPort : dPorts) {
175                 equalOrNotSetValidation(udpMatch.getUdpDestinationPort(), dstPort.longValue());
176                 udpMatches.add(new UdpMatchBuilder(udpMatch).setUdpDestinationPort(new PortNumber(dstPort.intValue()))
177                     .build());
178             }
179         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
180             for (Long srcPort : sPorts) {
181                 for (Long dstPort : dPorts) {
182                     equalOrNotSetValidation(udpMatch.getUdpSourcePort(), srcPort.longValue());
183                     equalOrNotSetValidation(udpMatch.getUdpDestinationPort(), dstPort.longValue());
184                     udpMatches.add(new UdpMatchBuilder(udpMatch).setUdpSourcePort(new PortNumber(srcPort.intValue()))
185                         .setUdpDestinationPort(new PortNumber(dstPort.intValue()))
186                         .build());
187                 }
188             }
189         }
190         return udpMatches;
191     }
192
193     private Set<TcpMatch> createTcpMatches(TcpMatch tcpMatch, Set<Long> sPorts, Set<Long> dPorts) {
194         Set<TcpMatch> tcpMatches = new HashSet<>();
195         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
196             for (Long srcPort : sPorts) {
197                 equalOrNotSetValidation(tcpMatch.getTcpSourcePort(), srcPort.longValue());
198                 tcpMatches.add(new TcpMatchBuilder(tcpMatch).setTcpSourcePort(new PortNumber(srcPort.intValue())).build());
199             }
200         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
201             for (Long dstPort : dPorts) {
202                 equalOrNotSetValidation(tcpMatch.getTcpDestinationPort(), dstPort.longValue());
203                 tcpMatches.add(new TcpMatchBuilder(tcpMatch).setTcpDestinationPort(new PortNumber(dstPort.intValue()))
204                     .build());
205             }
206         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
207             for (Long srcPort : sPorts) {
208                 for (Long dstPort : dPorts) {
209                     equalOrNotSetValidation(tcpMatch.getTcpSourcePort(), srcPort.longValue());
210                     equalOrNotSetValidation(tcpMatch.getTcpDestinationPort(), dstPort.longValue());
211                     tcpMatches.add(new TcpMatchBuilder(tcpMatch).setTcpSourcePort(new PortNumber(srcPort.intValue()))
212                         .setTcpDestinationPort(new PortNumber(dstPort.intValue()))
213                         .build());
214                 }
215             }
216         }
217         return tcpMatches;
218     }
219
220     private Set<SctpMatch> createSctpMatches(SctpMatch sctpMatch, Set<Long> sPorts, Set<Long> dPorts) {
221         Set<SctpMatch> sctpMatches = new HashSet<>();
222         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
223             for (Long srcPort : sPorts) {
224                 equalOrNotSetValidation(sctpMatch.getSctpSourcePort(), srcPort.longValue());
225                 sctpMatches.add(new SctpMatchBuilder(sctpMatch).setSctpSourcePort(new PortNumber(srcPort.intValue()))
226                     .build());
227             }
228         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
229             for (Long dstPort : dPorts) {
230                 equalOrNotSetValidation(sctpMatch.getSctpDestinationPort(), dstPort.longValue());
231                 sctpMatches.add(new SctpMatchBuilder(sctpMatch).setSctpDestinationPort(new PortNumber(dstPort.intValue()))
232                     .build());
233             }
234         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
235             for (Long srcPort : sPorts) {
236                 for (Long dstPort : dPorts) {
237                     equalOrNotSetValidation(sctpMatch.getSctpSourcePort(), srcPort.longValue());
238                     equalOrNotSetValidation(sctpMatch.getSctpDestinationPort(), dstPort.longValue());
239                     sctpMatches.add(new SctpMatchBuilder(sctpMatch).setSctpSourcePort(new PortNumber(srcPort.intValue()))
240                         .setSctpDestinationPort(new PortNumber(dstPort.intValue()))
241                         .build());
242                 }
243             }
244         }
245         return sctpMatches;
246     }
247
248     private void equalOrNotSetValidation(PortNumber portInMatch, long paramValue) {
249         if (portInMatch != null) {
250             if (paramValue != portInMatch.getValue().longValue()) {
251                 throw new IllegalArgumentException("Classification conflict detected for port values "
252                         + portInMatch.getValue().longValue() + " and " + paramValue + ". It is not allowed "
253                         + "to assign different values to the same parameter among all the classifiers within one rule.");
254             }
255         }
256     }
257
258     @Override
259     public void checkPrereqs(List<MatchBuilder> matches) {
260         for (MatchBuilder match : matches) {
261             Long proto = null;
262             try {
263                 proto = Long.valueOf(match.getIpMatch().getIpProtocol().longValue());
264             } catch (NullPointerException e) {
265                 throw new IllegalArgumentException("Parameter " + IpProtoClassifierDefinition.PROTO_PARAM + " is missing.");
266             }
267             if (!IpProtoClassifierDefinition.TCP_VALUE.equals(proto) && !IpProtoClassifierDefinition.UDP_VALUE.equals(proto)
268                     && !IpProtoClassifierDefinition.SCTP_VALUE.equals(proto)) {
269                 throw new IllegalArgumentException("Value of parameter " + IpProtoClassifierDefinition.PROTO_PARAM
270                         + " is not supported.");
271             }
272         }
273     }
274 }