2 * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved.
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
9 package org.opendaylight.netvirt.aclservice.utils;
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.List;
16 import org.opendaylight.genius.mdsalutil.MatchFieldType;
17 import org.opendaylight.genius.mdsalutil.MatchInfo;
18 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
19 import org.opendaylight.genius.mdsalutil.NwConstants;
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;
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.AceIp;
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.AceIpv4;
23 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;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRange;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.SourcePortRange;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
31 public class AclServiceOFFlowBuilder {
33 private static final Logger LOG =
34 LoggerFactory.getLogger(AclServiceOFFlowBuilder.class);
37 * Converts IP matches into flows.
40 * @return the map containing the flows and the respective flow id
42 public static Map<String, List<MatchInfoBase>> programIpFlow(Matches matches) {
43 if (matches != null) {
44 AceIp acl = (AceIp) matches.getAceType();
45 Short protocol = acl.getProtocol();
46 if (protocol == null) {
47 return programEtherFlow(acl);
48 } else if (acl.getProtocol() == NwConstants.IP_PROT_TCP) {
49 return programTcpFlow(acl);
50 } else if (acl.getProtocol() == NwConstants.IP_PROT_UDP) {
51 return programUdpFlow(acl);
52 } else if (acl.getProtocol() == NwConstants.IP_PROT_ICMP) {
53 return programIcmpFlow(acl);
54 } else if (acl.getProtocol() != -1) {
55 return programOtherProtocolFlow(acl);
61 /** Converts ether matches to flows.
62 * @param acl the access control list
63 * @return the map containing the flows and the respective flow id
65 public static Map<String,List<MatchInfoBase>> programEtherFlow(AceIp acl) {
66 List<MatchInfoBase> flowMatches = new ArrayList<>();
67 flowMatches.addAll(addSrcIpMatches(acl));
68 flowMatches.addAll(addDstIpMatches(acl));
69 String flowId = "ETHER" + acl.getProtocol();
70 Map<String,List<MatchInfoBase>> flowMatchesMap = new HashMap<>();
71 flowMatchesMap.put(flowId,flowMatches);
72 return flowMatchesMap;
75 /** Converts generic protocol matches to flows.
77 * @param acl the access control list
78 * @return the map containing the flows and the respective flow id
80 public static Map<String,List<MatchInfoBase>> programOtherProtocolFlow(AceIp acl) {
81 List<MatchInfoBase> flowMatches = new ArrayList<>();
82 flowMatches.addAll(addSrcIpMatches(acl));
83 flowMatches.addAll(addDstIpMatches(acl));
84 if (acl.getAceIpVersion() instanceof AceIpv4 ) {
85 flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
86 new long[] { NwConstants.ETHTYPE_IPV4 }));
87 } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
88 flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
89 new long[] { NwConstants.ETHTYPE_IPV6 }));
91 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
92 new long[] { acl.getProtocol() }));
93 String flowId = "OTHER_PROTO" + acl.getProtocol();
94 Map<String,List<MatchInfoBase>> flowMatchesMap = new HashMap<>();
95 flowMatchesMap.put(flowId,flowMatches);
96 return flowMatchesMap;
99 /**Converts icmp matches to flows.
100 * @param acl the access control list
101 * @return the map containing the flows and the respective flow id
103 public static Map<String,List<MatchInfoBase>> programIcmpFlow(AceIp acl) {
104 List<MatchInfoBase> flowMatches = new ArrayList<>();
105 flowMatches.addAll(addSrcIpMatches(acl));
106 flowMatches.addAll(addDstIpMatches(acl));
107 //For ICMP port range indicates type and code
108 SourcePortRange sourcePortRange = acl.getSourcePortRange();
109 String flowId = "ICMP_";
110 if (sourcePortRange != null) {
111 if (acl.getAceIpVersion() instanceof AceIpv4 ) {
112 flowMatches.add(new MatchInfo(MatchFieldType.icmp_v4,
113 new long[] { sourcePortRange.getLowerPort().getValue(),
114 sourcePortRange.getUpperPort().getValue() }));
115 flowId = flowId + "V4_SOURCE_" + sourcePortRange.getLowerPort().getValue()
116 + sourcePortRange.getUpperPort().getValue();
117 } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
118 flowMatches.add(new MatchInfo(MatchFieldType.icmp_v6,
119 new long[] { sourcePortRange.getLowerPort().getValue(),
120 sourcePortRange.getUpperPort().getValue() }));
121 flowId = flowId + "V6_SOURCE_" + sourcePortRange.getLowerPort().getValue() + "_"
122 + sourcePortRange.getUpperPort().getValue() + "_";
125 DestinationPortRange destinationPortRange = acl.getDestinationPortRange();
126 if (destinationPortRange != null) {
127 if (acl.getAceIpVersion() instanceof AceIpv4 ) {
128 flowMatches.add(new MatchInfo(MatchFieldType.icmp_v4,
129 new long[] { destinationPortRange.getLowerPort().getValue(),
130 destinationPortRange.getUpperPort().getValue() }));
131 flowId = flowId + "V4_DESTINATION_" + destinationPortRange.getLowerPort().getValue()
132 + destinationPortRange.getUpperPort().getValue() + "_";
133 } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
134 flowMatches.add(new MatchInfo(MatchFieldType.icmp_v6,
135 new long[] { destinationPortRange.getLowerPort().getValue(),
136 destinationPortRange.getUpperPort().getValue() }));
137 flowId = flowId + "V6_DESTINATION_" + destinationPortRange.getLowerPort().getValue()
138 + destinationPortRange.getUpperPort().getValue() + "_";
141 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
142 new long[] { acl.getProtocol() }));
143 Map<String,List<MatchInfoBase>> flowMatchesMap = new HashMap<>();
144 flowMatchesMap.put(flowId,flowMatches);
145 return flowMatchesMap;
148 /**Converts TCP matches to flows.
149 * @param acl the access control list
150 * @return the map containing the flows and the respective flow id
152 public static Map<String,List<MatchInfoBase>> programTcpFlow(AceIp acl) {
153 Map<String,List<MatchInfoBase>> flowMatchesMap = new HashMap<>();
154 SourcePortRange sourcePortRange = acl.getSourcePortRange();
155 DestinationPortRange destinationPortRange = acl.getDestinationPortRange();
156 if (sourcePortRange == null && destinationPortRange == null) {
157 List<MatchInfoBase> flowMatches = new ArrayList<>();
158 flowMatches.addAll(addSrcIpMatches(acl));
159 flowMatches.addAll(addDstIpMatches(acl));
160 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
161 new long[] { acl.getProtocol() }));
162 String flowId = "TCP_SOURCE_ALL_";
163 flowMatchesMap.put(flowId,flowMatches);
164 return flowMatchesMap;
166 if (sourcePortRange != null) {
167 Map<Integer, Integer> portMaskMap = getLayer4MaskForRange(sourcePortRange.getLowerPort().getValue(),
168 sourcePortRange.getUpperPort().getValue());
169 for (Integer port: portMaskMap.keySet()) {
170 List<MatchInfoBase> flowMatches = new ArrayList<>();
171 flowMatches.addAll(addSrcIpMatches(acl));
172 flowMatches.addAll(addDstIpMatches(acl));
173 flowMatches.add(new MatchInfo(MatchFieldType.tcp_src,
174 new long[] { port}));
175 /*flowMatches.add(new NxMatchInfo(NxMatchFieldType.nx_tcp_src_with_mask,
176 new long[] { port, portMaskMap.get(port) }));*/
177 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
178 new long[] { acl.getProtocol() }));
179 String flowId = "TCP_SOURCE_" + port + "_" + portMaskMap.get(port);
180 flowMatchesMap.put(flowId,flowMatches);
183 if (destinationPortRange != null) {
184 Map<Integer, Integer> portMaskMap = getLayer4MaskForRange(destinationPortRange.getLowerPort().getValue(),
185 destinationPortRange.getUpperPort().getValue());
186 for (Integer port: portMaskMap.keySet()) {
187 List<MatchInfoBase> flowMatches = new ArrayList<>();
188 flowMatches.addAll(addSrcIpMatches(acl));
189 flowMatches.addAll(addDstIpMatches(acl));
190 flowMatches.add(new MatchInfo(MatchFieldType.tcp_dst,
191 new long[] { port}));
192 /*flowMatches.add(new NxMatchInfo(NxMatchFieldType.nx_tcp_dst_with_mask,
193 new long[] { port, portMaskMap.get(port) }));*/
194 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
195 new long[] { acl.getProtocol() }));
196 String flowId = "TCP_DESTINATION_" + port + "_" + portMaskMap.get(port);
197 flowMatchesMap.put(flowId,flowMatches);
200 return flowMatchesMap;
203 /**Converts UDP matches to flows.
204 * @param acl the access control list
205 * @return the map containing the flows and the respective flow id
207 public static Map<String,List<MatchInfoBase>> programUdpFlow(AceIp acl) {
208 Map<String,List<MatchInfoBase>> flowMatchesMap = new HashMap<>();
209 SourcePortRange sourcePortRange = acl.getSourcePortRange();
210 DestinationPortRange destinationPortRange = acl.getDestinationPortRange();
211 if (sourcePortRange == null && destinationPortRange == null) {
212 List<MatchInfoBase> flowMatches = new ArrayList<>();
213 flowMatches.addAll(addSrcIpMatches(acl));
214 flowMatches.addAll(addDstIpMatches(acl));
215 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
216 new long[] { acl.getProtocol() }));
217 String flowId = "UDP_SOURCE_ALL_";
218 flowMatchesMap.put(flowId,flowMatches);
219 return flowMatchesMap;
221 if (sourcePortRange != null) {
222 Map<Integer, Integer> portMaskMap = getLayer4MaskForRange(sourcePortRange.getLowerPort().getValue(),
223 sourcePortRange.getUpperPort().getValue());
224 for (Integer port: portMaskMap.keySet()) {
225 List<MatchInfoBase> flowMatches = new ArrayList<>();
226 flowMatches.addAll(addSrcIpMatches(acl));
227 flowMatches.addAll(addDstIpMatches(acl));
228 flowMatches.add(new MatchInfo(MatchFieldType.udp_src,
229 new long[] { port}));
230 /*flowMatches.add(new NxMatchInfo(NxMatchFieldType.nx_udp_src_with_mask,
231 new long[] { port, portMaskMap.get(port) }));*/
232 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
233 new long[] { acl.getProtocol() }));
234 String flowId = "UDP_SOURCE_" + port + "_" + portMaskMap.get(port);
235 flowMatchesMap.put(flowId ,flowMatches);
238 if (destinationPortRange != null) {
239 Map<Integer, Integer> portMaskMap = getLayer4MaskForRange(destinationPortRange.getLowerPort().getValue(),
240 destinationPortRange.getUpperPort().getValue());
241 for (Integer port: portMaskMap.keySet()) {
242 List<MatchInfoBase> flowMatches = new ArrayList<>();
243 flowMatches.addAll(addSrcIpMatches(acl));
244 flowMatches.addAll(addDstIpMatches(acl));
245 flowMatches.add(new MatchInfo(MatchFieldType.udp_dst,
246 new long[] { port}));
247 /*flowMatches.add(new NxMatchInfo(NxMatchFieldType.nx_udp_dst_with_mask,
248 new long[] { port, portMaskMap.get(port) }));*/
249 flowMatches.add(new MatchInfo(MatchFieldType.ip_proto,
250 new long[] { acl.getProtocol() }));
251 String flowId = "UDP_DESTINATION_" + port + "_" + portMaskMap.get(port);
252 flowMatchesMap.put(flowId, flowMatches);
256 return flowMatchesMap;
259 /** Adds source ip matches to the flows.
260 * @param acl the access control list
261 * @return the list of flows.
263 public static List<MatchInfoBase> addSrcIpMatches(AceIp acl) {
264 List<MatchInfoBase> flowMatches = new ArrayList<>();
265 if (acl.getAceIpVersion() instanceof AceIpv4 ) {
266 flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
267 new long[] { NwConstants.ETHTYPE_IPV4 }));
268 Ipv4Prefix srcNetwork = ((AceIpv4)acl.getAceIpVersion()).getSourceIpv4Network();
269 if (null != srcNetwork) {
270 String[] ipaddressValues = srcNetwork.getValue().split("/");
271 flowMatches.add(new MatchInfo(MatchFieldType.ipv4_source,
272 new String[] {ipaddressValues[0], ipaddressValues[1]}));
274 } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
275 flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
276 new long[] { NwConstants.ETHTYPE_IPV6 }));
277 Ipv6Prefix srcNetwork = ((AceIpv6)acl.getAceIpVersion()).getSourceIpv6Network();
278 if (null != srcNetwork) {
285 /** Adds destination ip matches to the flows.
286 * @param acl the access control list
287 * @return the list of flows.
289 public static List<MatchInfoBase> addDstIpMatches(AceIp acl) {
290 List<MatchInfoBase> flowMatches = new ArrayList<>();
291 if (acl.getAceIpVersion() instanceof AceIpv4 ) {
292 flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
293 new long[] { NwConstants.ETHTYPE_IPV4 }));
294 Ipv4Prefix dstNetwork = ((AceIpv4)acl.getAceIpVersion()).getDestinationIpv4Network();
295 if (null != dstNetwork) {
296 String[] ipaddressValues = dstNetwork.getValue().split("/");
297 flowMatches.add(new MatchInfo(MatchFieldType.ipv4_destination,
298 new String[] {ipaddressValues[0], ipaddressValues[1]}));
300 } else if (acl.getAceIpVersion() instanceof AceIpv6 ) {
301 flowMatches.add(new MatchInfo(MatchFieldType.eth_type,
302 new long[] { NwConstants.ETHTYPE_IPV6 }));
303 Ipv6Prefix dstNetwork = ((AceIpv6)acl.getAceIpVersion()).getDestinationIpv6Network();
304 if (null != dstNetwork) {
312 * Converts port range into a set of masked port ranges.
314 * @param portMin the starting port of the range.
315 * @param portMax the ending port of the range.
316 * @return the map containing the port no and their mask.
319 public static Map<Integer,Integer> getLayer4MaskForRange(int portMin, int portMax) {
320 final int[] offset = { 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 };
321 final int[] mask = { 0x8000, 0xC000, 0xE000, 0xF000, 0xF800, 0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0,
322 0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF };
323 int noOfPorts = portMax - portMin + 1;
324 Map<Integer,Integer> portMap = new HashMap<>();
325 if (noOfPorts == 1) {
326 portMap.put(portMin, mask[15]);
329 if (noOfPorts < 0) { // TODO: replace with infrautils.counter in case of high repetitive usage
330 LOG.warn("Cannot convert port range into a set of masked port ranges - Illegal port range {}-{}", portMin,
334 String binaryNoOfPorts = Integer.toBinaryString(noOfPorts);
335 if (binaryNoOfPorts.length() > 16) { // TODO: replace with infrautils.counter in case of high repetitive usage
336 LOG.warn("Cannot convert port range into a set of masked port ranges - Illegal port range {}-{}", portMin,
340 int medianOffset = 16 - binaryNoOfPorts.length();
341 int medianLength = offset[medianOffset];
343 for (int tempMedian = 0;tempMedian < portMax;) {
344 tempMedian = medianLength + tempMedian;
345 if (portMin < tempMedian) {
351 int currentMedain = median;
352 for (int tempMedianOffset = medianOffset;16 > tempMedianOffset;tempMedianOffset++) {
353 tempMedian = currentMedain - offset[tempMedianOffset];
354 if (portMin <= tempMedian) {
355 for (;portMin <= tempMedian;) {
356 portMap.put(tempMedian, mask[tempMedianOffset]);
357 currentMedain = tempMedian;
358 tempMedian = tempMedian - offset[tempMedianOffset];
362 currentMedain = median;
363 for (int tempMedianOffset = medianOffset;16 > tempMedianOffset;tempMedianOffset++) {
364 tempMedian = currentMedain + offset[tempMedianOffset];
365 if (portMax >= tempMedian - 1) {
366 for (;portMax >= tempMedian - 1;) {
367 portMap.put(currentMedain, mask[tempMedianOffset]);
368 currentMedain = tempMedian;
369 tempMedian = tempMedian + offset[tempMedianOffset];