Added support for port range in TCP and UDP security group rules
authorAswin Suryanarayanan <aswin.suryanarayanan@hp.com>
Fri, 25 Dec 2015 00:37:15 +0000 (06:07 +0530)
committerAswin Suryanarayanan <aswin.suryanarayanan@hp.com>
Fri, 25 Dec 2015 00:54:10 +0000 (06:24 +0530)
Change-Id: I69ecc8eb52bedb641a7b2c4407b3e070ed2c1677
Signed-off-by: Aswin Suryanarayanan <aswin.suryanarayanan@hp.com>
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/EgressAclService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/IngressAclService.java
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/MatchUtils.java

index abce949d3901f51981e96fadc919d749ca24010e..710995ba285eef591bb0d3b36b5acbc963a3f749 100644 (file)
@@ -47,6 +47,7 @@ import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.List;
+import java.util.Map;
 
 public class EgressAclService extends AbstractServiceInstance implements EgressAclProvider, ConfigInterface {
 
@@ -293,6 +294,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
     private void egressAclTcp(Long dpidLong, String segmentationId, String srcMac,
                               NeutronSecurityRule portSecurityRule, String dstAddress,
                               boolean write, Integer protoPortMatchPriority) {
+        boolean portRange = false;
         MatchBuilder matchBuilder = new MatchBuilder();
         String flowId = "Egress_TCP_" + segmentationId + "_" + srcMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
@@ -309,10 +311,10 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
                             + portSecurityRule.getSecurityRulePortMax() + "_";
                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
+            } else {
+                portRange = true;
             }
-            /*TODO TCP PortRange Match*/
         }
-
         if (null != dstAddress) {
             flowId = flowId + dstAddress;
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
@@ -323,9 +325,22 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
                                       new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
         }
-        flowId = flowId + "_Permit";
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
-        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        if (portRange) {
+            Map<Integer, Integer> portMaskMap = MatchUtils
+                    .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
+                                           portSecurityRule.getSecurityRulePortMax());
+            for (Integer port: portMaskMap.keySet()) {
+                String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
+                rangeflowId = rangeflowId + "_Permit";
+                MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
+                                                  0, port, portMaskMap.get(port));
+                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+            }
+        } else {
+            flowId = flowId + "_Permit";
+            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        }
     }
 
     /**
@@ -389,7 +404,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
     private void egressAclUdp(Long dpidLong, String segmentationId, String srcMac,
                               NeutronSecurityRule portSecurityRule, String dstAddress,
                               boolean write, Integer protoPortMatchPriority) {
-
+        boolean portRange = false;
         MatchBuilder matchBuilder = new MatchBuilder();
         String flowId = "Egress_UDP_" + segmentationId + "_" + srcMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
@@ -406,24 +421,36 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
                     + portSecurityRule.getSecurityRulePortMax() + "_";
                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
+            } else {
+                portRange = true;
             }
-            /*TODO UDP PortRange Match*/
         }
-
         if (null != dstAddress) {
             flowId = flowId + dstAddress;
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
                                                         MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
-
         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
                                                         new Ipv4Prefix(portSecurityRule
                                                                        .getSecurityRuleRemoteIpPrefix()));
         }
-        flowId = flowId + "_Permit";
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
-        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        if (portRange) {
+            Map<Integer, Integer> portMaskMap = MatchUtils
+                    .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
+                                           portSecurityRule.getSecurityRulePortMax());
+            for (Integer port: portMaskMap.keySet()) {
+                String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
+                rangeflowId = rangeflowId + "_Permit";
+                MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
+                                                  0, port, portMaskMap.get(port));
+                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+            }
+        } else {
+            flowId = flowId + "_Permit";
+            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        }
     }
 
     public void egressACLDefaultTcpDrop(Long dpidLong, String segmentationId, String attachedMac,
index 319769874d07ad383db4313ee1d5b9ccf265029c..0a31568f188cd8bb21a216473e8571c0401476ca 100644 (file)
@@ -48,6 +48,7 @@ import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.List;
+import java.util.Map;
 
 public class IngressAclService extends AbstractServiceInstance implements IngressAclProvider, ConfigInterface {
     private static final Logger LOG = LoggerFactory.getLogger(IngressAclService.class);
@@ -263,7 +264,7 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
     private void ingressAclTcp(Long dpidLong, String segmentationId, String dstMac,
                                NeutronSecurityRule portSecurityRule, String srcAddress, boolean write,
                                Integer protoPortMatchPriority ) {
-
+        boolean portRange = false;
         MatchBuilder matchBuilder = new MatchBuilder();
         String flowId = "Ingress_TCP_" + segmentationId + "_" + dstMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
@@ -280,10 +281,10 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
                     + portSecurityRule.getSecurityRulePortMax() + "_";
                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
+            } else {
+                portRange = true;
             }
-            /*TODO TCP PortRange Match*/
         }
-
         if (null != srcAddress) {
             flowId = flowId + srcAddress;
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
@@ -296,8 +297,21 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                                                                        .getSecurityRuleRemoteIpPrefix()),null);
         }
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
-        flowId = flowId + "_Permit";
-        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        if (portRange) {
+            Map<Integer, Integer> portMaskMap = MatchUtils
+                    .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
+                                           portSecurityRule.getSecurityRulePortMax());
+            for (Integer port: portMaskMap.keySet()) {
+                String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
+                rangeflowId = rangeflowId + "_Permit";
+                MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
+                                                  0, port, portMaskMap.get(port));
+                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+            }
+        } else {
+            flowId = flowId + "_Permit";
+            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        }
     }
 
     /**
@@ -315,6 +329,7 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
     private void ingressAclUdp(Long dpidLong, String segmentationId, String dstMac,
                                NeutronSecurityRule portSecurityRule, String srcAddress,
                                boolean write, Integer protoPortMatchPriority ) {
+        boolean portRange = false;
         MatchBuilder matchBuilder = new MatchBuilder();
         String flowId = "Ingress_UDP_" + segmentationId + "_" + dstMac + "_";
         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
@@ -331,11 +346,10 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
                     + portSecurityRule.getSecurityRulePortMax() + "_";
                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
+            } else {
+                portRange = true;
             }
-            /*TODO TCP PortRange Match*/
-
         }
-
         if (null != srcAddress) {
             flowId = flowId + srcAddress;
             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
@@ -348,8 +362,21 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                                                                        .getSecurityRuleRemoteIpPrefix()),null);
         }
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
-        flowId = flowId + "_Permit";
-        syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        if (portRange) {
+            Map<Integer, Integer> portMaskMap = MatchUtils
+                    .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
+                                           portSecurityRule.getSecurityRulePortMax());
+            for (Integer port: portMaskMap.keySet()) {
+                String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
+                rangeflowId = rangeflowId + "_Permit";
+                MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
+                                                   0, port, portMaskMap.get(port));
+                syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+            }
+        } else {
+            flowId = flowId + "_Permit";
+            syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
+        }
     }
 
     /**
index 930a1d507b8f25a70e7aee8f517819346630e24f..33228f9ea40143110a3a8510b9ebc6eb9e93451a 100644 (file)
@@ -10,7 +10,9 @@ package org.opendaylight.ovsdb.utils.mdsal.openflow;
 
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
@@ -60,12 +62,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg6Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg7Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxTunIdKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfTcpDstKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfTcpSrcKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfUdpDstKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmOfUdpSrcKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.reg.grouping.NxmNxRegBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.tun.id.grouping.NxmNxTunIdBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNspKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsp.grouping.NxmNxNspBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNsiKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsi.grouping.NxmNxNsiBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.tcp.dst.grouping.NxmOfTcpDstBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.tcp.src.grouping.NxmOfTcpSrcBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.udp.dst.grouping.NxmOfUdpDstBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.of.udp.src.grouping.NxmOfUdpSrcBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -1041,7 +1051,7 @@ public class MatchUtils {
     /**
      * Add a layer4 match to an existing match
      *
-     * @param matchBuilder Map matchBuilder MatchBuilder Object without a match
+     * @param matchBuilder Map matchBuilder MatchBuilder Object with a match
      * @param protocol The layer4 protocol
      * @param srcPort The src port
      * @param destPort The destination port
@@ -1076,6 +1086,80 @@ public class MatchUtils {
         return matchBuilder;
     }
 
+    /**
+     * Add a layer4 match to an existing match with mask
+     *
+     * @param matchBuilder Map matchBuilder MatchBuilder Object with a match.
+     * @param protocol The layer4 protocol
+     * @param srcPort The src port
+     * @param destPort The destination port
+     * @param mask the mask for the port
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder addLayer4MatchWithMask(MatchBuilder matchBuilder,
+                                                      int protocol, int srcPort, int destPort,int mask) {
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+
+        NxAugMatchNodesNodeTableFlow nxAugMatch = null;
+        GeneralAugMatchNodesNodeTableFlow genAugMatch = null;
+        if (protocol == TCP_SHORT) {
+            ipmatch.setIpProtocol(TCP_SHORT);
+            if (0 != srcPort) {
+                NxmOfTcpSrcBuilder tcpSrc = new NxmOfTcpSrcBuilder();
+                tcpSrc.setPort(new PortNumber(srcPort));
+                tcpSrc.setMask(mask);
+                nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder().setNxmOfTcpSrc(tcpSrc.build()).build();
+                genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmOfTcpSrcKey.class)
+                                                   .setExtension(new ExtensionBuilder()
+                                                   .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                                 .build()).build())).build();
+            } else if (0 != destPort) {
+                NxmOfTcpDstBuilder tcpDst = new NxmOfTcpDstBuilder();
+                tcpDst.setPort(new PortNumber(destPort));
+                tcpDst.setMask(mask);
+                nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder()
+                .setNxmOfTcpDst(tcpDst.build())
+                .build();
+                genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmOfTcpDstKey.class)
+                                                   .setExtension(new ExtensionBuilder()
+                                                   .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                                 .build()).build())).build();
+            }
+
+        } else if (UDP_SHORT == protocol) {
+            ipmatch.setIpProtocol(UDP_SHORT);
+            UdpMatchBuilder udpMatch = new UdpMatchBuilder();
+            if (0 != srcPort) {
+                NxmOfUdpSrcBuilder udpSrc = new NxmOfUdpSrcBuilder();
+                udpSrc.setPort(new PortNumber(srcPort));
+                udpSrc.setMask(mask);
+                nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder().setNxmOfUdpSrc(udpSrc.build()).build();
+                genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmOfUdpSrcKey.class)
+                                                   .setExtension(new ExtensionBuilder()
+                                                   .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                                 .build()).build())).build();
+            } else if (0 != destPort) {
+                NxmOfUdpDstBuilder udpDst = new NxmOfUdpDstBuilder();
+                udpDst.setPort(new PortNumber(destPort));
+                udpDst.setMask(mask);
+                nxAugMatch = new NxAugMatchNodesNodeTableFlowBuilder()
+                .setNxmOfUdpDst(udpDst.build())
+                .build();
+                genAugMatch = new GeneralAugMatchNodesNodeTableFlowBuilder()
+                .setExtensionList(ImmutableList.of(new ExtensionListBuilder().setExtensionKey(NxmOfUdpDstKey.class)
+                                                   .setExtension(new ExtensionBuilder()
+                                                   .addAugmentation(NxAugMatchNodesNodeTableFlow.class, nxAugMatch)
+                                                                 .build()).build())).build();
+            }
+        }
+        matchBuilder.setIpMatch(ipmatch.build());
+        matchBuilder.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, genAugMatch);
+        return matchBuilder;
+    }
 
     public static class RegMatch {
         final Class<? extends NxmNxReg> reg;
@@ -1228,6 +1312,57 @@ public class MatchUtils {
         return new Ipv4Prefix(ipv4AddressString + "/32");
     }
 
+    /**
+     * Converts port range into a set of masked port ranges.
+     *
+     * @param portMin the strating port of the range.
+     * @param portMax the ending port of the range.
+     * @return the map contianing the port no and their mask.
+     *
+     */
+    public static Map<Integer,Integer>  getLayer4MaskForRange(int portMin, int portMax) {
+        int [] offset = {32768,16384,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1};
+        int[] mask = {0x8000,0xC000,0xE000,0xF000,0xF800,0xFC00,0xFE00,0xFF00,
+            0xFF80,0xFFC0,0xFFE0,0xFFF0,0xFFF8,0xFFFC,0xFFFE,0xFFFF};
+        int noOfPorts = portMax - portMin + 1;
+        String binaryNoOfPorts = Integer.toBinaryString(noOfPorts);
+        int medianOffset = 16 - binaryNoOfPorts.length();
+        int medianLength = offset[medianOffset];
+        int median = 0;
+        for (int tempMedian = 0;tempMedian < portMax;) {
+            tempMedian = medianLength + tempMedian;
+            if (portMin < tempMedian) {
+                median = tempMedian;
+                break;
+            }
+        }
+        Map<Integer,Integer> portMap = new HashMap<Integer,Integer>();
+        int tempMedian = 0;
+        int currentMedain = median;
+        for (int tempMedianOffset = medianOffset;16 > tempMedianOffset;tempMedianOffset++) {
+            tempMedian = currentMedain - offset[tempMedianOffset];
+            if (portMin <= tempMedian) {
+                for (;portMin <= tempMedian;) {
+                    portMap.put(tempMedian, mask[tempMedianOffset]);
+                    currentMedain = tempMedian;
+                    tempMedian = tempMedian - offset[tempMedianOffset];
+                }
+            }
+        }
+        currentMedain = median;
+        for (int tempMedianOffset = medianOffset;16 > tempMedianOffset;tempMedianOffset++) {
+            tempMedian = currentMedain + offset[tempMedianOffset];
+            if (portMax >= tempMedian - 1) {
+                for (;portMax >= tempMedian - 1;) {
+                    portMap.put(currentMedain, mask[tempMedianOffset]);
+                    currentMedain = tempMedian;
+                    tempMedian = tempMedian  + offset[tempMedianOffset];
+                }
+            }
+        }
+        return portMap;
+    }
+
     /**
      * Return Long that represents OF port for strings where OF is explicitly provided
      *