Merge "Fix for SingleFeatureTest wiring for neutron model"
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / utils / AclServiceOFFlowBuilder.java
1 /*
2  * Copyright (c) 2016 Red Hat, 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 package org.opendaylight.netvirt.aclservice.utils;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14
15 import org.opendaylight.genius.mdsalutil.MatchFieldType;
16 import org.opendaylight.genius.mdsalutil.MatchInfo;
17 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
18 import org.opendaylight.genius.mdsalutil.NwConstants;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRange;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.SourcePortRange;
27
28 public class AclServiceOFFlowBuilder {
29
30     private AclServiceOFFlowBuilder() {
31     }
32
33     /**
34      * Converts IP matches into flows.
35      * @param matches the matches
36      * @return the map containing the flows and the respective flow id
37      */
38     public static Map<String,List<MatchInfoBase>>  programIpFlow(Matches matches) {
39         new HashMap<>();
40         AceIp acl = (AceIp)matches.getAceType();
41         if (acl.getProtocol() == NwConstants.IP_PROT_TCP) {
42             return programTcpFlow(acl);
43         } else if (acl.getProtocol() == NwConstants.IP_PROT_UDP) {
44             return programUdpFlow(acl);
45         } else if (acl.getProtocol() == NwConstants.IP_PROT_ICMP) {
46             return programIcmpFlow(acl);
47         } else if (acl.getProtocol() != -1) {
48             return programOtherProtocolFlow(acl);
49         }
50         return null;
51
52     }
53
54     /** Converts generic protocol matches to flows.
55      *
56      * @param acl the access control list
57      * @return the map containing the flows and the respective flow id
58      */
59     public static Map<String,List<MatchInfoBase>> programOtherProtocolFlow(AceIp acl) {
60         List<MatchInfoBase> flowMatches = new ArrayList<>();
61         flowMatches.addAll(addSrcIpMatches(acl));
62         flowMatches.addAll(addDstIpMatches(acl));
63         if (acl.getAceIpVersion() instanceof AceIpv4 ) {
64             flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
65                 new long[] { NwConstants.ETHTYPE_IPV4 }));
66         } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
67             flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
68                 new long[] { NwConstants.ETHTYPE_IPV6 }));
69         }
70         flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
71             new long[] { acl.getProtocol() }));
72         String flowId = "OTHER_PROTO" + acl.getProtocol();
73         Map<String,List<MatchInfoBase>> flowMatchesMap = new HashMap<>();
74         flowMatchesMap.put(flowId,flowMatches);
75         return flowMatchesMap;
76     }
77
78     /**Converts icmp matches to flows.
79      * @param acl the access control list
80      * @return the map containing the flows and the respective flow id
81      */
82     public static Map<String,List<MatchInfoBase>> programIcmpFlow(AceIp acl) {
83         List<MatchInfoBase> flowMatches = new ArrayList<>();
84         flowMatches.addAll(addSrcIpMatches(acl));
85         flowMatches.addAll(addDstIpMatches(acl));
86         //For ICMP port range indicates type and code
87         SourcePortRange sourcePortRange = acl.getSourcePortRange();
88         String flowId = "ICMP_";
89         if (sourcePortRange != null) {
90             if (acl.getAceIpVersion() instanceof AceIpv4 ) {
91                 flowMatches.add(new MatchInfo(MatchFieldType.icmp_v4,
92                     new long[] { sourcePortRange.getLowerPort().getValue(),
93                                  sourcePortRange.getUpperPort().getValue() }));
94                 flowId = flowId + "V4_SOURCE_" + sourcePortRange.getLowerPort().getValue()
95                         + sourcePortRange.getUpperPort().getValue();
96             } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
97                 flowMatches.add(new MatchInfo(MatchFieldType.icmp_v6,
98                     new long[] { sourcePortRange.getLowerPort().getValue(),
99                                  sourcePortRange.getUpperPort().getValue() }));
100                 flowId = flowId + "V6_SOURCE_" + sourcePortRange.getLowerPort().getValue() + "_"
101                         + sourcePortRange.getUpperPort().getValue() + "_";
102             }
103         }
104         DestinationPortRange destinationPortRange = acl.getDestinationPortRange();
105         if (destinationPortRange != null) {
106             if (acl.getAceIpVersion() instanceof AceIpv4 ) {
107                 flowMatches.add(new MatchInfo(MatchFieldType.icmp_v4,
108                     new long[] { destinationPortRange.getLowerPort().getValue(),
109                                  destinationPortRange.getUpperPort().getValue() }));
110                 flowId = flowId + "V4_DESTINATION_" + destinationPortRange.getLowerPort().getValue()
111                         + destinationPortRange.getUpperPort().getValue() + "_";
112             } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
113                 flowMatches.add(new MatchInfo(MatchFieldType.icmp_v6,
114                     new long[] { destinationPortRange.getLowerPort().getValue(),
115                                  destinationPortRange.getUpperPort().getValue() }));
116                 flowId = flowId + "V6_DESTINATION_" + destinationPortRange.getLowerPort().getValue()
117                         + destinationPortRange.getUpperPort().getValue() + "_";
118             }
119         }
120         flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
121             new long[] { acl.getProtocol() }));
122         Map<String,List<MatchInfoBase>> flowMatchesMap = new HashMap<>();
123         flowMatchesMap.put(flowId,flowMatches);
124         return flowMatchesMap;
125     }
126
127     /**Converts TCP matches to flows.
128      * @param acl the access control list
129      * @return the map containing the flows and the respective flow id
130      */
131     public static Map<String,List<MatchInfoBase>> programTcpFlow(AceIp acl) {
132         Map<String,List<MatchInfoBase>> flowMatchesMap = new HashMap<>();
133         SourcePortRange sourcePortRange = acl.getSourcePortRange();
134         DestinationPortRange destinationPortRange = acl.getDestinationPortRange();
135         if (sourcePortRange == null && destinationPortRange == null) {
136             List<MatchInfoBase> flowMatches = new ArrayList<>();
137             flowMatches.addAll(addSrcIpMatches(acl));
138             flowMatches.addAll(addDstIpMatches(acl));
139             flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
140                 new long[] { acl.getProtocol() }));
141             String flowId = "TCP_SOURCE_ALL_";
142             flowMatchesMap.put(flowId,flowMatches);
143             return flowMatchesMap;
144         }
145         if (sourcePortRange != null) {
146             Map<Integer, Integer> portMaskMap = getLayer4MaskForRange(sourcePortRange.getLowerPort().getValue(),
147                 sourcePortRange.getUpperPort().getValue());
148             for (Integer port: portMaskMap.keySet()) {
149                 List<MatchInfoBase> flowMatches = new ArrayList<>();
150                 flowMatches.addAll(addSrcIpMatches(acl));
151                 flowMatches.addAll(addDstIpMatches(acl));
152                 flowMatches.add(new MatchInfo(MatchFieldType.tcp_src,
153                     new long[] { port}));
154                 /*flowMatches.add(new NxMatchInfo(NxMatchFieldType.nx_tcp_src_with_mask,
155                     new long[] {  port, portMaskMap.get(port) }));*/
156                 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
157                     new long[] { acl.getProtocol() }));
158                 String flowId = "TCP_SOURCE_" + port + "_" + portMaskMap.get(port);
159                 flowMatchesMap.put(flowId,flowMatches);
160             }
161         }
162         if (destinationPortRange != null) {
163             Map<Integer, Integer> portMaskMap = getLayer4MaskForRange(destinationPortRange.getLowerPort().getValue(),
164                 destinationPortRange.getUpperPort().getValue());
165             for (Integer port: portMaskMap.keySet()) {
166                 List<MatchInfoBase> flowMatches = new ArrayList<>();
167                 flowMatches.addAll(addSrcIpMatches(acl));
168                 flowMatches.addAll(addDstIpMatches(acl));
169                 flowMatches.add(new MatchInfo(MatchFieldType.tcp_dst,
170                         new long[] { port}));
171                 /*flowMatches.add(new NxMatchInfo(NxMatchFieldType.nx_tcp_dst_with_mask,
172                     new long[] {  port, portMaskMap.get(port) }));*/
173                 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
174                     new long[] { acl.getProtocol() }));
175                 String flowId = "TCP_DESTINATION_" + port + "_" + portMaskMap.get(port);
176                 flowMatchesMap.put(flowId,flowMatches);
177             }
178         }
179         return flowMatchesMap;
180     }
181
182     /**Converts UDP matches to flows.
183      * @param acl the access control list
184      * @return the map containing the flows and the respective flow id
185      */
186     public static Map<String,List<MatchInfoBase>> programUdpFlow(AceIp acl) {
187         Map<String,List<MatchInfoBase>> flowMatchesMap = new HashMap<>();
188         SourcePortRange sourcePortRange = acl.getSourcePortRange();
189         DestinationPortRange destinationPortRange = acl.getDestinationPortRange();
190         if (sourcePortRange == null && destinationPortRange == null) {
191             List<MatchInfoBase> flowMatches = new ArrayList<>();
192             flowMatches.addAll(addSrcIpMatches(acl));
193             flowMatches.addAll(addDstIpMatches(acl));
194             flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
195                 new long[] { acl.getProtocol() }));
196             String flowId = "UDP_SOURCE_ALL_";
197             flowMatchesMap.put(flowId,flowMatches);
198             return flowMatchesMap;
199         }
200         if (sourcePortRange != null) {
201             Map<Integer, Integer> portMaskMap = getLayer4MaskForRange(sourcePortRange.getLowerPort().getValue(),
202                 sourcePortRange.getUpperPort().getValue());
203             for (Integer port: portMaskMap.keySet()) {
204                 List<MatchInfoBase> flowMatches = new ArrayList<>();
205                 flowMatches.addAll(addSrcIpMatches(acl));
206                 flowMatches.addAll(addDstIpMatches(acl));
207                 flowMatches.add(new MatchInfo(MatchFieldType.udp_src,
208                     new long[] { port}));
209                 /*flowMatches.add(new NxMatchInfo(NxMatchFieldType.nx_udp_src_with_mask,
210                     new long[] {  port, portMaskMap.get(port) }));*/
211                 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
212                     new long[] { acl.getProtocol() }));
213                 String flowId = "UDP_SOURCE_" + port + "_" + portMaskMap.get(port);
214                 flowMatchesMap.put(flowId ,flowMatches);
215             }
216         }
217         if (destinationPortRange != null) {
218             Map<Integer, Integer> portMaskMap = getLayer4MaskForRange(destinationPortRange.getLowerPort().getValue(),
219                 destinationPortRange.getUpperPort().getValue());
220             for (Integer port: portMaskMap.keySet()) {
221                 List<MatchInfoBase> flowMatches = new ArrayList<>();
222                 flowMatches.addAll(addSrcIpMatches(acl));
223                 flowMatches.addAll(addDstIpMatches(acl));
224                 flowMatches.add(new MatchInfo(MatchFieldType.udp_dst,
225                     new long[] { port}));
226                 /*flowMatches.add(new NxMatchInfo(NxMatchFieldType.nx_udp_dst_with_mask,
227                     new long[] {  port, portMaskMap.get(port) }));*/
228                 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
229                     new long[] { acl.getProtocol() }));
230                 String flowId = "UDP_DESTINATION_" + port + "_" + portMaskMap.get(port);
231                 flowMatchesMap.put(flowId, flowMatches);
232             }
233         }
234
235         return flowMatchesMap;
236     }
237
238     /** Adds source ip matches to the flows.
239      * @param acl the access control list
240      * @return the list of flows.
241      */
242     public static List<MatchInfoBase> addSrcIpMatches(AceIp acl) {
243         List<MatchInfoBase> flowMatches = new ArrayList<>();
244         if (acl.getAceIpVersion() instanceof AceIpv4 ) {
245             flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
246                 new long[] { NwConstants.ETHTYPE_IPV4 }));
247             Ipv4Prefix srcNetwork = ((AceIpv4)acl.getAceIpVersion()).getSourceIpv4Network();
248             if (null != srcNetwork) {
249                 String[] ipaddressValues = srcNetwork.getValue().split("/");
250                 flowMatches.add(new MatchInfo(MatchFieldType.ipv4_source,
251                     new String[] {ipaddressValues[0], ipaddressValues[1]}));
252             }
253         } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
254             flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
255                 new long[] { NwConstants.ETHTYPE_IPV6 }));
256             Ipv6Prefix srcNetwork = ((AceIpv6)acl.getAceIpVersion()).getSourceIpv6Network();
257             if (null != srcNetwork) {
258                 // TODO Ipv6 Match.
259             }
260         }
261         return flowMatches;
262     }
263
264     /** Adds destination ip matches to the flows.
265      * @param acl the access control list
266      * @return the list of flows.
267      */
268     public static List<MatchInfoBase> addDstIpMatches(AceIp acl) {
269         List<MatchInfoBase> flowMatches = new ArrayList<>();
270         if (acl.getAceIpVersion() instanceof AceIpv4 ) {
271             flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
272                 new long[] { NwConstants.ETHTYPE_IPV4 }));
273             Ipv4Prefix dstNetwork = ((AceIpv4)acl.getAceIpVersion()).getDestinationIpv4Network();
274             if (null != dstNetwork) {
275                 String[] ipaddressValues = dstNetwork.getValue().split("/");
276                 flowMatches.add(new MatchInfo(MatchFieldType.ipv4_destination,
277                     new String[] {ipaddressValues[0], ipaddressValues[1]}));
278             }
279         } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
280             flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
281                 new long[] { NwConstants.ETHTYPE_IPV6 }));
282             Ipv6Prefix dstNetwork = ((AceIpv6)acl.getAceIpVersion()).getDestinationIpv6Network();
283             if (null != dstNetwork) {
284              // TODO Ipv6 Match.
285             }
286         }
287         return flowMatches;
288     }
289
290     /**
291      * Converts port range into a set of masked port ranges.
292      *
293      * @param portMin the starting port of the range.
294      * @param portMax the ending port of the range.
295      * @return the map containing the port no and their mask.
296      *
297      */
298     public static Map<Integer,Integer>  getLayer4MaskForRange(int portMin, int portMax) {
299         int [] offset = {32768,16384,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1};
300         int[] mask = {0x8000,0xC000,0xE000,0xF000,0xF800,0xFC00,0xFE00,0xFF00,
301                       0xFF80,0xFFC0,0xFFE0,0xFFF0,0xFFF8,0xFFFC,0xFFFE,0xFFFF};
302         int noOfPorts = portMax - portMin + 1;
303         Map<Integer,Integer> portMap = new HashMap<>();
304         if (noOfPorts == 1) {
305             portMap.put(portMin, mask[15]);
306             return portMap;
307         }
308         String binaryNoOfPorts = Integer.toBinaryString(noOfPorts);
309         int medianOffset = 16 - binaryNoOfPorts.length();
310         int medianLength = offset[medianOffset];
311         int median = 0;
312         for (int tempMedian = 0;tempMedian < portMax;) {
313             tempMedian = medianLength + tempMedian;
314             if (portMin < tempMedian) {
315                 median = tempMedian;
316                 break;
317             }
318         }
319         int tempMedian = 0;
320         int currentMedain = median;
321         for (int tempMedianOffset = medianOffset;16 > tempMedianOffset;tempMedianOffset++) {
322             tempMedian = currentMedain - offset[tempMedianOffset];
323             if (portMin <= tempMedian) {
324                 for (;portMin <= tempMedian;) {
325                     portMap.put(tempMedian, mask[tempMedianOffset]);
326                     currentMedain = tempMedian;
327                     tempMedian = tempMedian - offset[tempMedianOffset];
328                 }
329             }
330         }
331         currentMedain = median;
332         for (int tempMedianOffset = medianOffset;16 > tempMedianOffset;tempMedianOffset++) {
333             tempMedian = currentMedain + offset[tempMedianOffset];
334             if (portMax >= tempMedian - 1) {
335                 for (;portMax >= tempMedian - 1;) {
336                     portMap.put(currentMedain, mask[tempMedianOffset]);
337                     currentMedain = tempMedian;
338                     tempMedian = tempMedian  + offset[tempMedianOffset];
339                 }
340             }
341         }
342         return portMap;
343     }
344
345 }