4f32e54dbc20520291a83c3a3d4ffdbf8dad6edb
[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 import java.util.ArrayList;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
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.IsRequired;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
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.TcpMatch;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import com.google.common.collect.ImmutableList;
40 import com.google.common.collect.ImmutableMap;
41
42 /**
43  * Match against TCP or UDP, and source and/or destination ports
44  */
45 public class L4Classifier extends IpProtoClassifier {
46     private static final Logger LOG = LoggerFactory.getLogger(L4Classifier.class);
47     public static final ClassifierDefinitionId ID = 
48             new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f");
49     private static final String SPORT = "sourceport";
50     private static final String SPORT_RANGE = "sourceport_range";
51     private static final String DPORT = "destport";
52     private static final String DPORT_RANGE = "destport_range";
53     private static final ClassifierDefinition DEF =
54             new ClassifierDefinitionBuilder()
55                 .setId(new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f"))
56                 .setParent(IpProtoClassifier.ID)
57                 .setName(new ClassifierName("l4"))
58                 .setDescription(new Description("Match on the port number of UDP or TCP traffic"))
59                 .setParameter(ImmutableList.of(new ParameterBuilder()
60                                 .setName(new ParameterName(SPORT))
61                                 .setDescription(new Description("The source port number to match against"))
62                                 .setType(Type.Int)
63                                 .build(),
64                         new ParameterBuilder()
65                                 .setName(new ParameterName(SPORT_RANGE))
66                                 .setDescription(new Description("The source port range to match against"))
67                                 .setType(Type.Range)
68                                 .build(),
69                         new ParameterBuilder()
70                                 .setName(new ParameterName(DPORT))
71                                 .setDescription(new Description("The destination port number to match against"))
72                                 .setType(Type.Int)
73                                 .build(),
74                         new ParameterBuilder()
75                                 .setName(new ParameterName(DPORT_RANGE))
76                                 .setDescription(new Description("The destination port range to match against"))
77                                 .setType(Type.Range)
78                                 .build(),
79                         new ParameterBuilder()
80                                 .setName(new ParameterName(TYPE))
81                                 .setDescription(new Description("TCP or UDP"))
82                                 .setIsRequired(IsRequired.Required)
83                                 .setType(Type.String)
84                                 .build()))
85                 .build();
86     
87     private static final Map<String, Object> tcp = 
88             ImmutableMap.<String,Object>of(PROTO, Long.valueOf(6));
89     private static final Map<String, Object> udp = 
90             ImmutableMap.<String,Object>of(PROTO, Long.valueOf(17));
91     
92     @Override
93     public ClassifierDefinitionId getId() {
94         return ID;
95     }
96
97     @Override
98     public ClassifierDefinition getClassDef() {
99         return DEF;
100     }
101
102     @Override
103     public List<MatchBuilder> updateMatch(List<MatchBuilder> matches,
104                                           Map<String, Object> params) {
105         Object param = params.get(TYPE);
106         // XXX TODO generate exception and fail the match
107         if (param == null || !(param instanceof String)) return matches;
108         String type = (String) param;
109
110         if ("UDP".equals(type))
111             matches = super.updateMatch(matches, udp);
112         else
113             matches = super.updateMatch(matches, tcp);
114
115         Set<Long> sPorts = new HashSet<>();
116         Set<Long> dPorts = new HashSet<>();
117         // int-value and range parameters
118         param = params.get(SPORT);
119         if (param != null && (param instanceof Long))
120             sPorts.add((long) param);
121         param = params.get(DPORT);
122         if (param != null && (param instanceof Long))
123             dPorts.add((long) param);
124         param = params.get(SPORT_RANGE);
125         if (param != null && param instanceof RangeValue) {
126             sPorts.addAll(createSetFromRange((RangeValue) param));
127         }
128         param = params.get(DPORT_RANGE);
129         if (param != null && param instanceof RangeValue) {
130             dPorts.addAll(createSetFromRange((RangeValue) param));
131         }
132
133         Set<? extends Layer4Match> l4Matches = null;
134         if ("UDP".equals(type)) {
135             l4Matches = createUdpMatches(sPorts, dPorts);
136         } else {
137             l4Matches = createTcpMatches(sPorts, dPorts);
138         }
139         List<MatchBuilder> newMatches = new ArrayList<>();
140         for (MatchBuilder matchBuilder : matches) {
141             Match baseMatch = matchBuilder.build();
142             for (Layer4Match l4Match : l4Matches) {
143                 newMatches.add(new MatchBuilder(baseMatch).setLayer4Match(l4Match));
144             }
145         }
146         return newMatches;
147     }
148
149     private Set<Long> createSetFromRange(RangeValue rangeValueParam){
150         Set<Long> res = new HashSet<>();
151         if (rangeValueParam != null) {
152             final Long min = rangeValueParam.getMin();
153             final Long max = rangeValueParam.getMax();
154             if (min <= max) {
155                 for (long val = min; val <= max; val++) {
156                     res.add(val);
157                 }
158             } else {
159                 LOG.warn("Range value mismatch. MIN {} is greater than MAX {}.", min, max);
160             }
161         }
162         return res;
163     }
164
165     private Set<UdpMatch> createUdpMatches(Set<Long> sPorts, Set<Long> dPorts) {
166         Set<UdpMatch> udpMatches = new HashSet<>();
167         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
168             for (Long srcPort : sPorts) {
169                 udpMatches.add(new UdpMatchBuilder().setUdpSourcePort(new PortNumber(srcPort.intValue())).build());
170             }
171         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
172             for (Long dstPort : dPorts) {
173                 udpMatches.add(new UdpMatchBuilder().setUdpDestinationPort(new PortNumber(dstPort.intValue())).build());
174             }
175         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
176             for (Long srcPort : sPorts) {
177                 for (Long dstPort : dPorts) {
178                     udpMatches.add(new UdpMatchBuilder().setUdpSourcePort(new PortNumber(srcPort.intValue()))
179                             .setUdpDestinationPort(new PortNumber(dstPort.intValue())).build());
180                 }
181             }
182         }
183         return udpMatches;
184     }
185
186     private Set<TcpMatch> createTcpMatches(Set<Long> sPorts, Set<Long> dPorts) {
187         Set<TcpMatch> tcpMatches = new HashSet<>();
188         if (!sPorts.isEmpty() && dPorts.isEmpty()) {
189             for (Long srcPort : sPorts) {
190                 tcpMatches.add(new TcpMatchBuilder().setTcpSourcePort(new PortNumber(srcPort.intValue())).build());
191             }
192         } else if (sPorts.isEmpty() && !dPorts.isEmpty()) {
193             for (Long dstPort : dPorts) {
194                 tcpMatches
195                         .add(new TcpMatchBuilder().setTcpDestinationPort(new PortNumber(dstPort.intValue())).build());
196             }
197         } else if (!sPorts.isEmpty() && !dPorts.isEmpty()) {
198             for (Long srcPort : sPorts) {
199                 for (Long dstPort : dPorts) {
200                     tcpMatches.add(new TcpMatchBuilder().setTcpSourcePort(new PortNumber(srcPort.intValue()))
201                             .setTcpDestinationPort(new PortNumber(dstPort.intValue())).build());
202                 }
203             }
204         }
205         return tcpMatches;
206     }
207 }