Bug-5119 - Adding support for L3 address arbitraty bit mask with Unittests coverage...
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / match / MatchConvertorImpl.java
index e41912152091658c49aa8a0752ee35f0ad5025a5..a78f48968b8844b17180c0219bc51f80edfc1f1a 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match;
 
 import static org.opendaylight.openflowjava.util.ByteBufUtils.macAddressToString;
-
 import com.google.common.base.Optional;
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
@@ -29,12 +28,14 @@ import org.opendaylight.openflowplugin.openflow.md.util.ActionUtil;
 import org.opendaylight.openflowplugin.openflow.md.util.ByteUtil;
 import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IetfInetUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 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.Ipv6Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6FlowLabel;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.field._case.SetField;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.field._case.SetFieldBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
@@ -68,14 +69,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TunnelBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.TunnelIpv4Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.TunnelIpv4MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.*;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
@@ -275,6 +269,19 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
     private static final short PROTO_ICMPV4 = 1;
     private static final String NO_IP = "0.0.0.0/0";
 
+    // Pre-calculated masks for the 33 possible values. Do not give them out, but clone() them as they may
+    // end up being leaked and vulnerable.
+    private static final byte[][] IPV4_MASKS;
+    static {
+        final byte[][] tmp = new byte[33][];
+        for (int i = 0; i <= 32; ++i) {
+            final int mask = 0xffffffff << (32 - i);
+            tmp[i] =  new byte[]{(byte) (mask >>> 24), (byte) (mask >>> 16), (byte) (mask >>> 8), (byte) mask};
+        }
+
+        IPV4_MASKS = tmp;
+    }
+
     @Override
     public List<MatchEntry> convert(
             final org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match match, final BigInteger datapathid) {
@@ -351,8 +358,8 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
     }
 
 
-    private void protocolMatchFields(List<MatchEntry> matchEntryList,
-            ProtocolMatchFields protocolMatchFields) {
+    private static void protocolMatchFields(final List<MatchEntry> matchEntryList,
+            final ProtocolMatchFields protocolMatchFields) {
         if (protocolMatchFields != null) {
             if (protocolMatchFields.getMplsLabel() != null) {
                 matchEntryList.add(toOfMplsLabel(protocolMatchFields.getMplsLabel()));
@@ -373,10 +380,60 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
     }
 
 
-    private void layer3Match(List<MatchEntry> matchEntryList,
-            Layer3Match layer3Match) {
+    private static void layer3Match(final List<MatchEntry> matchEntryList, final Layer3Match layer3Match) {
         if (layer3Match != null) {
-            if (layer3Match instanceof Ipv4Match) {
+            if(layer3Match instanceof Ipv4MatchArbitraryBitMask) {
+                Ipv4MatchArbitraryBitMask ipv4MatchArbitraryBitMaskFields = (Ipv4MatchArbitraryBitMask) layer3Match;
+                if (ipv4MatchArbitraryBitMaskFields.getIpv4SourceAddressNoMask() != null) {
+                    MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
+                    matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
+                    matchEntryBuilder.setOxmMatchField(Ipv4Src.class);
+
+                    Ipv4SrcCaseBuilder ipv4SrcCaseBuilder = new Ipv4SrcCaseBuilder();
+                    Ipv4SrcBuilder ipv4SrcBuilder = new Ipv4SrcBuilder();
+
+                    ipv4SrcBuilder.setIpv4Address(ipv4MatchArbitraryBitMaskFields.getIpv4SourceAddressNoMask());
+                    DottedQuad sourceArbitrarySubNetMask = ipv4MatchArbitraryBitMaskFields.getIpv4SourceArbitraryBitmask();
+
+                    boolean hasMask = false;
+                    if (sourceArbitrarySubNetMask != null) {
+                        byte[] maskByteArray = IpConversionUtil.convertArbitraryMaskToByteArray(sourceArbitrarySubNetMask);
+                        if (maskByteArray != null) {
+                            ipv4SrcBuilder.setMask(maskByteArray);
+                            hasMask = true;
+                        }
+                    }
+                    matchEntryBuilder.setHasMask(hasMask);
+                    ipv4SrcCaseBuilder.setIpv4Src(ipv4SrcBuilder.build());
+                    matchEntryBuilder.setMatchEntryValue(ipv4SrcCaseBuilder.build());
+                    matchEntryList.add(matchEntryBuilder.build());
+                }
+                if (ipv4MatchArbitraryBitMaskFields.getIpv4DestinationAddressNoMask() != null) {
+                    MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
+                    matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
+                    matchEntryBuilder.setOxmMatchField(Ipv4Dst.class);
+
+                    Ipv4DstCaseBuilder ipv4DstCaseBuilder = new Ipv4DstCaseBuilder();
+                    Ipv4DstBuilder ipv4DstBuilder = new Ipv4DstBuilder();
+
+                    ipv4DstBuilder.setIpv4Address(ipv4MatchArbitraryBitMaskFields.getIpv4DestinationAddressNoMask());
+                    DottedQuad destArbitrarySubNetMask = ipv4MatchArbitraryBitMaskFields.getIpv4DestinationArbitraryBitmask();
+
+                    boolean hasMask = false;
+                    if (destArbitrarySubNetMask != null) {
+                        byte[] maskByteArray = IpConversionUtil.convertArbitraryMaskToByteArray(destArbitrarySubNetMask);
+                        if (maskByteArray != null) {
+                            ipv4DstBuilder.setMask(maskByteArray);
+                            hasMask = true;
+                        }
+                    }
+                    matchEntryBuilder.setHasMask(hasMask);
+                    ipv4DstCaseBuilder.setIpv4Dst(ipv4DstBuilder.build());
+                    matchEntryBuilder.setMatchEntryValue(ipv4DstCaseBuilder.build());
+                    matchEntryList.add(matchEntryBuilder.build());
+                }
+            }
+            if(layer3Match instanceof Ipv4Match){
                 Ipv4Match ipv4Match = (Ipv4Match) layer3Match;
                 if (ipv4Match.getIpv4Source() != null) {
                     Ipv4Prefix ipv4Prefix = ipv4Match.getIpv4Source();
@@ -657,8 +714,7 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
     }
 
 
-    private void icmpv6Match(List<MatchEntry> matchEntryList,
-            Icmpv6Match icmpv6Match) {
+    private static void icmpv6Match(final List<MatchEntry> matchEntryList, final Icmpv6Match icmpv6Match) {
         if (icmpv6Match != null) {
             if (icmpv6Match.getIcmpv6Type() != null) {
                 matchEntryList.add(toOfIcmpv6Type(icmpv6Match.getIcmpv6Type()));
@@ -671,8 +727,7 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
     }
 
 
-    private void icmpv4Match(List<MatchEntry> matchEntryList,
-            Icmpv4Match icmpv4Match) {
+    private static void icmpv4Match(final List<MatchEntry> matchEntryList, final Icmpv4Match icmpv4Match) {
         if (icmpv4Match != null) {
             if (icmpv4Match.getIcmpv4Type() != null) {
                 matchEntryList.add(toOfIcmpv4Type(icmpv4Match.getIcmpv4Type()));
@@ -685,8 +740,7 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
     }
 
 
-    private void layer4Match(List<MatchEntry> matchEntryList,
-            Layer4Match layer4Match) {
+    private static void layer4Match(final List<MatchEntry> matchEntryList, final Layer4Match layer4Match) {
         if (layer4Match != null) {
             if (layer4Match instanceof TcpMatch) {
                 TcpMatch tcpMatch = (TcpMatch) layer4Match;
@@ -782,7 +836,7 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
     }
 
 
-    private void ipMatch(List<MatchEntry> matchEntryList, IpMatch ipMatch) {
+    private static void ipMatch(final List<MatchEntry> matchEntryList, final IpMatch ipMatch) {
         if (ipMatch != null) {
             if (ipMatch.getIpDscp() != null) {
                 matchEntryList.add(toOfIpDscp(ipMatch.getIpDscp()));
@@ -795,13 +849,11 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
             if (ipMatch.getIpProtocol() != null) {
                 matchEntryList.add(toOfIpProto(ipMatch.getIpProtocol()));
             }
-
         }
     }
 
 
-    private void vlanMatch(List<MatchEntry> matchEntryList,
-            VlanMatch vlanMatch) {
+    private static void vlanMatch(final List<MatchEntry> matchEntryList, final VlanMatch vlanMatch) {
         if (vlanMatch != null) {
             if (vlanMatch.getVlanId() != null) {
                 VlanId vlanId = vlanMatch.getVlanId();
@@ -840,8 +892,7 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
     }
 
 
-    private void ethernetMatch(List<MatchEntry> matchEntryList,
-            EthernetMatch ethernetMatch) {
+    private static void ethernetMatch(final List<MatchEntry> matchEntryList, final EthernetMatch ethernetMatch) {
         if (ethernetMatch != null) {
             EthernetDestination ethernetDestination = ethernetMatch.getEthernetDestination();
             if (ethernetDestination != null) {
@@ -899,10 +950,8 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
         }
 
         if (prefix != 0) {
-            int mask = 0xffffffff << (32 - prefix);
-            byte[] maskBytes = new byte[]{(byte) (mask >>> 24), (byte) (mask >>> 16), (byte) (mask >>> 8),
-                    (byte) mask};
-            return maskBytes;
+            // clone() is necessary to protect our constants
+            return IPV4_MASKS[prefix].clone();
         }
         return null;
     }
@@ -959,36 +1008,34 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
             matchBuilder.setVlanMatch(vlanMatchBuilder.build());
         }
         if (!swMatch.getWildcards().isDLTYPE().booleanValue() && swMatch.getNwSrc() != null) {
-            String ipv4PrefixStr = swMatch.getNwSrc().getValue();
+            final Ipv4Prefix prefix;
             if (swMatch.getNwSrcMask() != null) {
-                ipv4PrefixStr += IpConversionUtil.PREFIX_SEPARATOR + swMatch.getNwSrcMask();
+                prefix = IetfInetUtil.INSTANCE.ipv4PrefixFor(swMatch.getNwSrc(), swMatch.getNwSrcMask());
             } else {
                 //Openflow Spec : 1.3.2
                 //An all-one-bits oxm_mask is equivalent to specifying 0 for oxm_hasmask and omitting oxm_mask.
                 // So when user specify 32 as a mast, switch omit that mast and we get null as a mask in flow
                 // statistics response.
-
-                ipv4PrefixStr += IpConversionUtil.PREFIX_SEPARATOR + "32";
+                prefix = IetfInetUtil.INSTANCE.ipv4PrefixFor(swMatch.getNwSrc());
             }
-            if (!NO_IP.equals(ipv4PrefixStr)) {
-                ipv4MatchBuilder.setIpv4Source(new Ipv4Prefix(ipv4PrefixStr));
+            if (!NO_IP.equals(prefix.getValue())) {
+                ipv4MatchBuilder.setIpv4Source(prefix);
                 matchBuilder.setLayer3Match(ipv4MatchBuilder.build());
             }
         }
         if (!swMatch.getWildcards().isDLTYPE().booleanValue() && swMatch.getNwDst() != null) {
-            String ipv4PrefixStr = swMatch.getNwDst().getValue();
+            final Ipv4Prefix prefix;
             if (swMatch.getNwDstMask() != null) {
-                ipv4PrefixStr += IpConversionUtil.PREFIX_SEPARATOR + swMatch.getNwDstMask();
+                prefix = IetfInetUtil.INSTANCE.ipv4PrefixFor(swMatch.getNwDst(), swMatch.getNwDstMask());
             } else {
                 //Openflow Spec : 1.3.2
                 //An all-one-bits oxm_mask is equivalent to specifying 0 for oxm_hasmask and omitting oxm_mask.
                 // So when user specify 32 as a mast, switch omit that mast and we get null as a mask in flow
                 // statistics response.
-
-                ipv4PrefixStr += IpConversionUtil.PREFIX_SEPARATOR + "32";
+                prefix = IetfInetUtil.INSTANCE.ipv4PrefixFor(swMatch.getNwDst());
             }
-            if (!NO_IP.equals(ipv4PrefixStr)) {
-                ipv4MatchBuilder.setIpv4Destination(new Ipv4Prefix(ipv4PrefixStr));
+            if (!NO_IP.equals(prefix.getValue())) {
+                ipv4MatchBuilder.setIpv4Destination(prefix);
                 matchBuilder.setLayer3Match(ipv4MatchBuilder.build());
             }
         }
@@ -1097,6 +1144,7 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
         Icmpv4MatchBuilder icmpv4MatchBuilder = new Icmpv4MatchBuilder();
         Icmpv6MatchBuilder icmpv6MatchBuilder = new Icmpv6MatchBuilder();
         Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder();
+        Ipv4MatchArbitraryBitMaskBuilder ipv4MatchArbitraryBitMaskBuilder = new Ipv4MatchArbitraryBitMaskBuilder();
         ArpMatchBuilder arpMatchBuilder = new ArpMatchBuilder();
         Ipv6MatchBuilder ipv6MatchBuilder = new Ipv6MatchBuilder();
         ProtocolMatchFieldsBuilder protocolMatchFieldsBuilder = new ProtocolMatchFieldsBuilder();
@@ -1268,17 +1316,33 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
                 org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.ipv4.src._case.Ipv4Src ipv4Address = ((Ipv4SrcCase) ofMatch.getMatchEntryValue()).getIpv4Src();
                 if (ipv4Address != null) {
                     byte[] mask = ipv4Address.getMask();
-                    String ipv4PrefixStr = ipv4Address.getIpv4Address().getValue();
-                    setIpv4MatchBuilderFields(ipv4MatchBuilder, ofMatch, mask, ipv4PrefixStr);
-                    matchBuilder.setLayer3Match(ipv4MatchBuilder.build());
+                    if (mask != null && IpConversionUtil.isArbitraryBitMask(mask)) {
+                        DottedQuad dottedQuadMask = IpConversionUtil.createArbitraryBitMask(mask);
+                        String Ipv4Address = ipv4Address.getIpv4Address().getValue();
+                        setIpv4MatchArbitraryBitMaskBuilderFields(ipv4MatchArbitraryBitMaskBuilder, ofMatch, dottedQuadMask, Ipv4Address);
+                        matchBuilder.setLayer3Match(ipv4MatchArbitraryBitMaskBuilder.build());
+                    }
+                    else {
+                        String ipv4PrefixStr = ipv4Address.getIpv4Address().getValue();
+                        setIpv4MatchBuilderFields(ipv4MatchBuilder, ofMatch, mask, ipv4PrefixStr);
+                        matchBuilder.setLayer3Match(ipv4MatchBuilder.build());
+                    }
                 }
             } else if (ofMatch.getOxmMatchField().equals(Ipv4Dst.class)) {
                 org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.ipv4.dst._case.Ipv4Dst ipv4Address = ((Ipv4DstCase) ofMatch.getMatchEntryValue()).getIpv4Dst();
                 if (ipv4Address != null) {
                     byte[] mask = ipv4Address.getMask();
-                    String ipv4PrefixStr = ipv4Address.getIpv4Address().getValue();
-                    setIpv4MatchBuilderFields(ipv4MatchBuilder, ofMatch, mask, ipv4PrefixStr);
-                    matchBuilder.setLayer3Match(ipv4MatchBuilder.build());
+                    if(mask != null && IpConversionUtil.isArbitraryBitMask(mask)) {
+                        DottedQuad dottedQuadMask = IpConversionUtil.createArbitraryBitMask(mask);
+                        String Ipv4Address = ipv4Address.getIpv4Address().getValue();
+                        setIpv4MatchArbitraryBitMaskBuilderFields(ipv4MatchArbitraryBitMaskBuilder, ofMatch, dottedQuadMask, Ipv4Address);
+                        matchBuilder.setLayer3Match(ipv4MatchArbitraryBitMaskBuilder.build());
+                    }
+                    else {
+                        String ipv4PrefixStr = ipv4Address.getIpv4Address().getValue();
+                        setIpv4MatchBuilderFields(ipv4MatchBuilder, ofMatch, mask, ipv4PrefixStr);
+                        matchBuilder.setLayer3Match(ipv4MatchBuilder.build());
+                    }
                 }
             } else if (ofMatch.getOxmMatchField().equals(TunnelIpv4Dst.class)
                     || ofMatch.getOxmMatchField().equals(TunnelIpv4Src.class)) {
@@ -1490,7 +1554,7 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
     }
 
     private static void setIpv4MatchBuilderFields(final Ipv4MatchBuilder ipv4MatchBuilder, final MatchEntry ofMatch, final byte[] mask, final String ipv4PrefixStr) {
-        Ipv4Prefix ipv4Prefix;
+        final Ipv4Prefix ipv4Prefix;
         if (mask != null) {
             ipv4Prefix = IpConversionUtil.createPrefix(new Ipv4Address(ipv4PrefixStr), mask);
         } else {
@@ -1508,6 +1572,27 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
         }
     }
 
+    private static void setIpv4MatchArbitraryBitMaskBuilderFields(final Ipv4MatchArbitraryBitMaskBuilder ipv4MatchArbitraryBitMaskBuilder, final MatchEntry ofMatch, final DottedQuad mask, final String ipv4AddressStr) {
+        Ipv4Address ipv4Address;
+        DottedQuad dottedQuad;
+        if (mask != null) {
+            dottedQuad = mask;
+            if (ofMatch.getOxmMatchField().equals(Ipv4Src.class)) {
+                ipv4MatchArbitraryBitMaskBuilder.setIpv4SourceArbitraryBitmask(dottedQuad);
+            }
+            if (ofMatch.getOxmMatchField().equals(Ipv4Dst.class)) {
+                ipv4MatchArbitraryBitMaskBuilder.setIpv4DestinationArbitraryBitmask(dottedQuad);
+            }
+        }
+        ipv4Address = new Ipv4Address(ipv4AddressStr);
+        if (ofMatch.getOxmMatchField().equals(Ipv4Src.class)) {
+            ipv4MatchArbitraryBitMaskBuilder.setIpv4SourceAddressNoMask(ipv4Address);
+        }
+        if (ofMatch.getOxmMatchField().equals(Ipv4Dst.class)) {
+            ipv4MatchArbitraryBitMaskBuilder.setIpv4DestinationAddressNoMask(ipv4Address);
+        }
+    }
+
 
     private static MatchEntry toOfMplsPbb(final Pbb pbb) {
         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
@@ -1838,5 +1923,4 @@ public class MatchConvertorImpl implements MatchConvertor<List<MatchEntry>> {
         return setField.build();
     }
 
-
 }