From ae735b4aacfc7008b0c12425367a419b47646350 Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Thu, 13 Oct 2016 15:16:39 +0200 Subject: HONEYCOMB-218: add support for TCP/UDP port ranges * can be used in combination with any other L2/L3 rule. * assumes no ip options / extension headers * provides naive implementation (vpp classfier api limitation): every (src, dst) is mapped to single classify session. Change-Id: Id6aa249b3e19f0aa47b9e15b5477d56bc70bee0e Signed-off-by: Marek Gradzki --- .../interfaces/acl/ingress/AceEthWriterTest.java | 2 +- .../interfaces/acl/ingress/AceIp4WriterTest.java | 27 +++-- .../interfaces/acl/ingress/AceIp6WriterTest.java | 27 +++-- .../acl/ingress/AceIpAndEthWriterTest.java | 15 ++- .../acl/ingress/AceIpWriterTestUtils.java | 6 +- .../v3po/interfaces/acl/ingress/PortPairTest.java | 114 +++++++++++++++++++++ 6 files changed, 167 insertions(+), 24 deletions(-) create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPairTest.java (limited to 'v3po/v3po2vpp/src/test/java/io/fd/honeycomb') diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriterTest.java index 546de89d7..cfff1e81c 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriterTest.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriterTest.java @@ -76,7 +76,7 @@ public class AceEthWriterTest { @Test public void testCreateClassifySession() { final int tableIndex = 123; - final ClassifyAddDelSession request = writer.createSession(action, aceEth, InterfaceMode.L2, tableIndex, 0); + final ClassifyAddDelSession request = writer.createSession(action, aceEth, InterfaceMode.L2, tableIndex, 0).get(0); assertEquals(1, request.isAdd); assertEquals(tableIndex, request.tableIndex); diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4WriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4WriterTest.java index 258a937ac..948e5f95b 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4WriterTest.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4WriterTest.java @@ -31,6 +31,9 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.cont import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Dscp; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; public class AceIp4WriterTest { @@ -51,6 +54,8 @@ public class AceIp4WriterTest { .setSourceIpv4Network(new Ipv4Prefix("1.2.3.4/32")) .setDestinationIpv4Network(new Ipv4Prefix("1.2.4.5/24")) .build()) + .setSourcePortRange(new SourcePortRangeBuilder().setLowerPort(new PortNumber(0x1111)).build()) + .setDestinationPortRange(new DestinationPortRangeBuilder().setLowerPort(new PortNumber(0x2222)).build()) .build(); } @@ -75,14 +80,17 @@ public class AceIp4WriterTest { -1, -1, -1, -1, // destination address: -1, -1, -1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + // source and destination port: + -1, -1, -1, -1, + // padding: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (isL2) { expectedMask[12] = (byte) 0xff; expectedMask[13] = (byte) 0xff; } - AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMask, request.mask, vlanTags * VLAN_TAG_LEN); + AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMask, expectedMask.length, request.mask, vlanTags * VLAN_TAG_LEN); } @@ -103,14 +111,17 @@ public class AceIp4WriterTest { 1, 2, 3, 4, // destination address: 1, 2, 4, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + // source and destination port: + 0x11, 0x11, 0x22, 0x22, + // padding: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (isL2) { expectedMatch[12] = (byte) 0x08; expectedMatch[13] = (byte) 0x00; } - AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMatch, request.match, vlanTags * VLAN_TAG_LEN); + AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMatch, expectedMatch.length, request.match, vlanTags * VLAN_TAG_LEN); } @@ -147,14 +158,14 @@ public class AceIp4WriterTest { @Test public void testCreateClassifySession() throws Exception { final int tableIndex = 123; - final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, 0); + final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, 0).get(0); verifySessionRequest(request, tableIndex, 0, false); } @Test public void testCreateClassifySessionForL2Interface() throws Exception { final int tableIndex = 123; - final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L2, tableIndex, 0); + final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L2, tableIndex, 0).get(0); verifySessionRequest(request, tableIndex, 0, true); } @@ -162,7 +173,7 @@ public class AceIp4WriterTest { public void testCreateClassifySession1VlanTag() throws Exception { final int tableIndex = 123; final int vlanTags = 1; - final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags); + final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); verifySessionRequest(request, tableIndex, vlanTags, false); } @@ -170,7 +181,7 @@ public class AceIp4WriterTest { public void testCreateClassifySession2VlanTags() throws Exception { final int tableIndex = 123; final int vlanTags = 2; - final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags); + final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); verifySessionRequest(request, tableIndex, vlanTags, false); } diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6WriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6WriterTest.java index 08f90557e..b45fb418c 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6WriterTest.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6WriterTest.java @@ -32,6 +32,9 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.cont import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Dscp; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6FlowLabel; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; public class AceIp6WriterTest { @@ -53,6 +56,8 @@ public class AceIp6WriterTest { .setSourceIpv6Network(new Ipv6Prefix("2001:db8:85a3:8d3:1319:8a2e:370:7348/128")) .setDestinationIpv6Network(new Ipv6Prefix("fe80:1234:5678:abcd:ef01::/64")) .build()) + .setSourcePortRange(new SourcePortRangeBuilder().setLowerPort(new PortNumber(0x1111)).build()) + .setDestinationPortRange(new DestinationPortRangeBuilder().setLowerPort(new PortNumber(0x2222)).build()) .build(); } @@ -64,7 +69,7 @@ public class AceIp6WriterTest { assertEquals(1, request.nbuckets); assertEquals(nextTableIndex, request.nextTableIndex); assertEquals(0, request.skipNVectors); - assertEquals(AceIp6Writer.MATCH_N_VECTORS, request.matchNVectors); + assertEquals(vlanTags == 2 ? 5 : 4, request.matchNVectors); assertEquals(AceIp6Writer.TABLE_MEM_SIZE, request.memorySize); byte[] expectedMask = new byte[] { @@ -80,15 +85,17 @@ public class AceIp6WriterTest { // destination address: (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0, 0, 0, 0, 0, 0, 0, 0, + // source and destination port: + -1, -1, -1, -1, // padding to multiple of 16B: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }; if (isL2) { expectedMask[12] = (byte) 0xff; expectedMask[13] = (byte) 0xff; } - AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMask, request.mask, vlanTags * VLAN_TAG_LEN); + AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMask, vlanTags == 2 ? 80 : 64, request.mask, vlanTags * VLAN_TAG_LEN); } private static void verifySessionRequest(final ClassifyAddDelSession request, final int tableIndex, @@ -110,15 +117,17 @@ public class AceIp6WriterTest { // destination address: (byte) 0xfe, (byte) 0x80, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0xab, (byte) 0xcd, 0, 0, 0, 0, 0, 0, 0, 0, + // source and destination port: + 0x11, 0x11, 0x22, 0x22, // padding to multiple of 16B: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }; if (isL2) { expectedMatch[12] = (byte) 0x86; expectedMatch[13] = (byte) 0xdd; } - AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMatch, request.match, vlanTags * VLAN_TAG_LEN); + AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMatch, vlanTags == 2 ? 80 : 64, request.match, vlanTags * VLAN_TAG_LEN); } @@ -160,7 +169,7 @@ public class AceIp6WriterTest { public void testCreateClassifySession() { final int tableIndex = 123; final ClassifyAddDelSession request = - writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, 0); + writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, 0).get(0); verifySessionRequest(request, tableIndex, 0, false); } @@ -168,7 +177,7 @@ public class AceIp6WriterTest { public void testCreateClassifySessionForL2Interface() { final int tableIndex = 123; final ClassifyAddDelSession request = - writer.createSession(action, aceIp, InterfaceMode.L2, tableIndex, 0); + writer.createSession(action, aceIp, InterfaceMode.L2, tableIndex, 0).get(0); verifySessionRequest(request, tableIndex, 0, true); } @@ -177,7 +186,7 @@ public class AceIp6WriterTest { final int tableIndex = 123; final int vlanTags = 1; final ClassifyAddDelSession request = - writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags); + writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); verifySessionRequest(request, tableIndex, vlanTags, false); } @@ -186,7 +195,7 @@ public class AceIp6WriterTest { final int tableIndex = 123; final int vlanTags = 2; final ClassifyAddDelSession request = - writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags); + writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); verifySessionRequest(request, tableIndex, vlanTags, false); } } \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriterTest.java index 1da23072b..7739f0f7f 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriterTest.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriterTest.java @@ -27,6 +27,9 @@ import org.junit.Test; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.packet.handling.DenyBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpAndEth; @@ -49,6 +52,8 @@ public class AceIpAndEthWriterTest { .setSourceMacAddress(new MacAddress("aa:bb:cc:dd:ee:ff")) .setAceIpVersion(new AceIpv4Builder() .setSourceIpv4Network(new Ipv4Prefix("1.2.3.4/32")).build()) + .setSourcePortRange(new SourcePortRangeBuilder().setLowerPort(new PortNumber(0x1111)).build()) + .setDestinationPortRange(new DestinationPortRangeBuilder().setLowerPort(new PortNumber(0x2222)).build()) .build(); } @@ -78,8 +83,10 @@ public class AceIpAndEthWriterTest { -1, -1, -1, -1, // destination address: 0, 0, 0, 0, + // source and destination port: + -1, -1, -1, -1, // padding: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; assertArrayEquals(expectedMask, request.mask); } @@ -87,7 +94,7 @@ public class AceIpAndEthWriterTest { @Test public void testCreateClassifySession() { final int tableIndex = 123; - final ClassifyAddDelSession request = writer.createSession(action, ace, InterfaceMode.L2, tableIndex, 0); + final ClassifyAddDelSession request = writer.createSession(action, ace, InterfaceMode.L2, tableIndex, 0).get(0); assertEquals(1, request.isAdd); assertEquals(tableIndex, request.tableIndex); @@ -106,8 +113,10 @@ public class AceIpAndEthWriterTest { 1, 2, 3, 4, // destination address: 0, 0, 0, 0, + // source and destination port: + 0x11, 0x11, 0x22, 0x22, // padding: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; assertArrayEquals(expectedMatch, request.match); } diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpWriterTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpWriterTestUtils.java index 7deb61f19..e7e29916c 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpWriterTestUtils.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpWriterTestUtils.java @@ -24,10 +24,10 @@ final class AceIpWriterTestUtils { throw new UnsupportedOperationException("This utility class cannot be instantiated"); } - protected static void assertArrayEqualsWithOffset(final byte[] baseExpected, final byte[] actual, + protected static void assertArrayEqualsWithOffset(final byte[] baseExpected, final int expectedLength, final byte[] actual, final int offset) { - byte[] expected = new byte[baseExpected.length]; - System.arraycopy(baseExpected, 0, expected, offset, expected.length - offset); + byte[] expected = new byte[expectedLength]; + System.arraycopy(baseExpected, 0, expected, offset, Math.min(baseExpected.length, expectedLength-offset)); assertArrayEquals(expected, actual); } diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPairTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPairTest.java new file mode 100644 index 000000000..b02c411ff --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPairTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasSize; + +import java.util.List; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRange; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRange; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; + +public class PortPairTest { + + @Test + public void testSingleSrc() { + final SourcePortRange src = new SourcePortRangeBuilder().setLowerPort(new PortNumber(123)).build(); + final List portPairs = PortPair.fromRange(src, null); + assertThat(portPairs, hasSize(1)); + assertThat(portPairs, contains(new PortPair(123, null))); + } + + @Test + public void testSrcRange() { + final SourcePortRange src = new SourcePortRangeBuilder() + .setLowerPort(new PortNumber(123)) + .setUpperPort(new PortNumber(125)).build(); + final List portPairs = PortPair.fromRange(src, null); + assertThat(portPairs, hasSize(3)); + assertThat(portPairs, contains(new PortPair(123, null), new PortPair(124, null), new PortPair(125, null))); + } + + @Test + public void testSrcRangeWithDst() { + final SourcePortRange src = new SourcePortRangeBuilder() + .setLowerPort(new PortNumber(123)) + .setUpperPort(new PortNumber(125)).build(); + final DestinationPortRange dst = new DestinationPortRangeBuilder().setLowerPort(new PortNumber(111)).build(); + final List portPairs = PortPair.fromRange(src, dst); + assertThat(portPairs, hasSize(3)); + assertThat(portPairs, contains(new PortPair(123, 111), new PortPair(124, 111), new PortPair(125, 111))); + } + + @Test + public void testSingleDst() { + final DestinationPortRange dst = new DestinationPortRangeBuilder().setLowerPort(new PortNumber(123)).build(); + final List portPairs = PortPair.fromRange(null, dst); + assertThat(portPairs, hasSize(1)); + assertThat(portPairs, contains(new PortPair(null, 123))); + } + + @Test + public void testDstRange() { + final DestinationPortRange dst = new DestinationPortRangeBuilder() + .setLowerPort(new PortNumber(10)) + .setUpperPort(new PortNumber(11)).build(); + final List portPairs = PortPair.fromRange(null, dst); + assertThat(portPairs, hasSize(2)); + assertThat(portPairs, contains(new PortPair(null, 10), new PortPair(null, 11))); + } + + @Test + public void testDstRangeWithSrc() { + final SourcePortRange src = new SourcePortRangeBuilder().setLowerPort(new PortNumber(111)).build(); + final DestinationPortRange dst = new DestinationPortRangeBuilder() + .setLowerPort(new PortNumber(10)) + .setUpperPort(new PortNumber(11)).build(); + final List portPairs = PortPair.fromRange(src, dst); + assertThat(portPairs, hasSize(2)); + assertThat(portPairs, contains(new PortPair(111, 10), new PortPair(111, 11))); + } + + @Test + public void testSinglePair() { + final SourcePortRange src = new SourcePortRangeBuilder().setLowerPort(new PortNumber(123)).build(); + final DestinationPortRange dst = new DestinationPortRangeBuilder().setLowerPort(new PortNumber(321)).build(); + final List portPairs = PortPair.fromRange(src, dst); + assertThat(portPairs, hasSize(1)); + assertThat(portPairs, contains(new PortPair(123, 321))); + } + + @Test + public void testCartesianProduct() { + final SourcePortRange src = new SourcePortRangeBuilder() + .setLowerPort(new PortNumber(1)) + .setUpperPort(new PortNumber(2)).build(); + final DestinationPortRange dst = new DestinationPortRangeBuilder() + .setLowerPort(new PortNumber(1)) + .setUpperPort(new PortNumber(3)).build(); + final List portPairs = PortPair.fromRange(src, dst); + assertThat(portPairs, hasSize(6)); + assertThat(portPairs, + contains(new PortPair(1, 1), new PortPair(1, 2), new PortPair(1, 3), new PortPair(2, 1), new PortPair(2, 2), + new PortPair(2, 3))); + } +} \ No newline at end of file -- cgit 1.2.3-korg