From e2a08e75fe3d98854c1ae7da7c75253dd2ec45b3 Mon Sep 17 00:00:00 2001 From: Hideyuki Tai Date: Fri, 20 Jun 2014 05:06:36 -0400 Subject: [PATCH] Bug 1212: Values of VLAN match fields were wrong. Values of match fields for VLAN tag were wrong when used AD-SAL OF plugin and tried to create a flow entry which matched packets without VLAN tags. V6Match class of AD-SAL OF plugin didn't have code for handling packets without VLAN tags. Changes: * Added code for handling packets without VLAN tags to V6Match class. * Added test cases related to the change of V6Match class. Change-Id: Ic9c3a6c47c7e99d5273e48ec2ed8d0399289cddb Signed-off-by: Hideyuki Tai --- .../vendorextension/v6extension/V6Match.java | 84 +++- .../v6extension/V6MatchTest.java | 461 ++++++++++++++++++ 2 files changed, 533 insertions(+), 12 deletions(-) create mode 100644 opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6MatchTest.java diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java index cfe20a1fa2..4b8966c546 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -69,6 +69,16 @@ public class V6Match extends OFMatch implements Cloneable { private static int IPV6_EXT_MIN_HDR_LEN = 36; + /** + * CFI bit in VLAN TCI field. + */ + private static final int VLAN_TCI_CFI = 1 << 12; + + /** + * Value of OFP_VLAN_NONE defined by OpenFlow 1.0. + */ + private static final short OFP_VLAN_NONE = (short) 0xffff; + private enum MatchFieldState { MATCH_ABSENT, MATCH_FIELD_ONLY, MATCH_FIELD_WITH_MASK } @@ -334,11 +344,15 @@ public class V6Match extends OFMatch implements Cloneable { private byte[] getVlanTCI(short dataLayerVirtualLanID, byte dataLayerVirtualLanPriorityCodePoint) { ByteBuffer vlan_tci = ByteBuffer.allocate(2); - int cfi = 1 << 12; // the cfi bit is in position 12 - int pcp = dataLayerVirtualLanPriorityCodePoint << 13; // the pcp fields - // have to move by - // 13 - int vlan_tci_int = pcp + cfi + dataLayerVirtualLanID; + int vlan_tci_int; + if (dataLayerVirtualLanID == OFP_VLAN_NONE) { + // Match only packets without VLAN tag. + vlan_tci_int = 0; + } else { + // the pcp fields have to move by 13 + int pcp = dataLayerVirtualLanPriorityCodePoint << 13; + vlan_tci_int = pcp + VLAN_TCI_CFI + dataLayerVirtualLanID; + } vlan_tci.put((byte) (vlan_tci_int >> 8)); // bits 8 to 15 vlan_tci.put((byte) vlan_tci_int); // bits 0 to 7 return vlan_tci.array(); @@ -542,7 +556,12 @@ public class V6Match extends OFMatch implements Cloneable { ethTypeState = MatchFieldState.MATCH_FIELD_ONLY; match_len += 6; } else if (values[0].equals(STR_DL_VLAN)) { - this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1])); + short vlan = U16.t(Integer.valueOf(values[1])); + if (this.dlVlanPCPState != MatchFieldState.MATCH_ABSENT && + vlan == OFP_VLAN_NONE) { + throw new IllegalArgumentException("DL_VLAN_PCP is set."); + } + this.dataLayerVirtualLan = vlan; this.dlVlanIDState = MatchFieldState.MATCH_FIELD_ONLY; // the variable dlVlanIDState is not really used as a flag // for serializing and deserializing. Rather it is used as a @@ -552,6 +571,9 @@ public class V6Match extends OFMatch implements Cloneable { if (this.dlVlanPCPState != MatchFieldState.MATCH_ABSENT) { this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; match_len -= 2; + } else if (this.dataLayerVirtualLan == OFP_VLAN_NONE) { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; + match_len += 6; } else { this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; this.dataLayerVirtualLanTCIMask = 0x1fff; @@ -559,6 +581,11 @@ public class V6Match extends OFMatch implements Cloneable { } this.wildcards &= ~OFPFW_DL_VLAN; } else if (values[0].equals(STR_DL_VLAN_PCP)) { + if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT && + this.dataLayerVirtualLan == OFP_VLAN_NONE) { + throw new IllegalArgumentException + ("OFP_VLAN_NONE is specified to DL_VLAN."); + } this.dataLayerVirtualLanPriorityCodePoint = U8.t(Short .valueOf(values[1])); this.dlVlanPCPState = MatchFieldState.MATCH_FIELD_ONLY; @@ -858,12 +885,20 @@ public class V6Match extends OFMatch implements Cloneable { // get the vlan pcp byte firstByte = data.get(); byte secondByte = data.get(); - super.setDataLayerVirtualLanPriorityCodePoint(getVlanPCP(firstByte)); - super.setDataLayerVirtualLan(getVlanID(firstByte, secondByte)); + if (firstByte == 0 && secondByte == 0) { + // Match only packets without VLAN tag. + setDataLayerVirtualLan(OFP_VLAN_NONE); + } else if (((firstByte << 8) & VLAN_TCI_CFI) == 0) { + // Ignore invalid TCI field. + return; + } else { + super.setDataLayerVirtualLanPriorityCodePoint(getVlanPCP(firstByte)); + super.setDataLayerVirtualLan(getVlanID(firstByte, secondByte)); + this.wildcards ^= (1 << 20); + } this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 6; this.wildcards ^= (1 << 1); // Sync with 0F 1.0 Match - this.wildcards ^= (1 << 20); } } } @@ -1241,7 +1276,6 @@ public class V6Match extends OFMatch implements Cloneable { * * @return */ - public Inet6Address getNetworkDest() { return this.nwDst; } @@ -1251,7 +1285,6 @@ public class V6Match extends OFMatch implements Cloneable { * * @return */ - public Inet6Address getNetworkSrc() { return this.nwSrc; } @@ -1316,7 +1349,19 @@ public class V6Match extends OFMatch implements Cloneable { } } + /** + * Set a value to VLAN ID match field. + * + * @param vlan A value to match for VLAN ID. + * @param mask A bitmask for VLAN ID. + */ public void setDataLayerVirtualLan(short vlan, short mask) { + if (vlan == OFP_VLAN_NONE + && this.dlVlanIDState != MatchFieldState.MATCH_ABSENT) { + throw new IllegalStateException + ("DL_VLAN_PCP is set."); + } + // mask is ignored as the code sets the appropriate mask super.dataLayerVirtualLan = vlan; this.dlVlanIDState = MatchFieldState.MATCH_FIELD_ONLY; @@ -1327,6 +1372,9 @@ public class V6Match extends OFMatch implements Cloneable { if (this.dlVlanPCPState != MatchFieldState.MATCH_ABSENT) { this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; match_len -= 2; + } else if (this.dataLayerVirtualLan == OFP_VLAN_NONE) { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; + match_len += 6; } else { this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; this.dataLayerVirtualLanTCIMask = 0x1fff; @@ -1334,7 +1382,19 @@ public class V6Match extends OFMatch implements Cloneable { } } + /** + * Set a value to VLAN PCP match field. + * + * @param pcp A value to match for VLAN PCP. + * @param mask A bitmask for VLAN PCP. + */ public void setDataLayerVirtualLanPriorityCodePoint(byte pcp, byte mask) { + if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT + && this.dataLayerVirtualLan == OFP_VLAN_NONE) { + throw new IllegalStateException + ("OFP_VLAN_NONE is specified to DL_VLAN."); + } + // mask is ignored as the code sets the appropriate mask super.dataLayerVirtualLanPriorityCodePoint = pcp; this.dlVlanPCPState = MatchFieldState.MATCH_FIELD_ONLY; diff --git a/opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6MatchTest.java b/opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6MatchTest.java new file mode 100644 index 0000000000..fceaaf46c9 --- /dev/null +++ b/opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6MatchTest.java @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2014 NEC Corporation + * All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this + * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.openflow.protocol.OFMatch.OFPFW_ALL; +import static org.openflow.protocol.OFMatch.OFPFW_DL_VLAN; +import static org.openflow.protocol.OFMatch.OFPFW_DL_VLAN_PCP; +import static org.openflow.protocol.OFMatch.OFPFW_IN_PORT; + +import java.nio.ByteBuffer; +import org.junit.Test; + +/** + * JUnit test for {@link V6Match}. + */ +public class V6MatchTest { + /** + * Header of a match entry for input port field without a mask. + * The vendor-specific value is 0, and the length of value is 2. + */ + private static int HEADER_INPUT_PORT = (0 << 9) | 2; + + /** + * Header of a match entry for VLAN TCI field without a mask. + * The vendor-specific value is 4, and the length of value is 2. + */ + private static int HEADER_VLAN_TCI= (4 << 9) | 2; + + /** + * Header of a match entry for VLAN TCI field with a mask. + * The vendor-specific value is 4, and the length of value is 4. + */ + private static int HEADER_VLAN_TCI_W = (4 << 9) | (1 << 8) | 4; + + /** + * Length of a match entry for input port field. + * Header (4 bytes) + value (2 bytes) = 6 bytes. + */ + private static short MATCH_LEN_INPUT_PORT = 6; + + /** + * Length of a match entry for VLAN TCI field without a mask. + * Header (4 bytes) + value (2 bytes) = 6 bytes. + */ + private static short MATCH_LEN_VLAN_TCI = 6; + + /** + * Length of a match entry for VLAN TCI field with a mask. + * Header (4 bytes) + value (2 bytes) + bitmask (2 bytes) = 8 bytes. + */ + private static short MATCH_LEN_VLAN_TCI_WITH_MASK = 8; + + /** + * Value of OFP_VLAN_NONE defined by OpenFlow 1.0. + */ + private static final short OFP_VLAN_NONE = (short)0xffff; + + /** + * CFI bit in VLAN TCI field. + */ + private static final int VLAN_TCI_CFI = 1 << 12; + + /** + * Test case for {@link V6Match#fromString(String)} about VLAN TCI field. + * This test passes values to "dl_vlan" and "dl_vpcp". + */ + @Test + public void testFromStringVlanTci() { + // Test for "dl_vlan" using non OFP_VLAN_NONE values. + short vlans[] = {1, 10, 1000, 4095}; + short mask = 0; + for (short vlan: vlans) { + V6Match match = new V6Match(); + match.fromString("dl_vlan=" + vlan); + assertEquals(MATCH_LEN_VLAN_TCI_WITH_MASK, match.getIPv6MatchLen()); + assertEquals(vlan, match.getDataLayerVirtualLan()); + int wildcards = OFPFW_ALL & ~OFPFW_DL_VLAN; + assertEquals(wildcards, match.getWildcards()); + } + + // Test for "dl_vpcp". + byte pcps[] = {1, 3, 7}; + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.fromString("dl_vpcp=" + pcp); + assertEquals(MATCH_LEN_VLAN_TCI_WITH_MASK, match.getIPv6MatchLen()); + assertEquals(pcp, match.getDataLayerVirtualLanPriorityCodePoint()); + int wildcards = OFPFW_ALL & ~OFPFW_DL_VLAN_PCP; + assertEquals(wildcards, match.getWildcards()); + } + + // Set "dl_vlan" field firstly, "dl_vpcp" field secondly. + for (short vlan: vlans) { + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.fromString("dl_vlan=" + vlan); + match.fromString("dl_vpcp=" + pcp); + assertEquals(MATCH_LEN_VLAN_TCI, match.getIPv6MatchLen()); + assertEquals(vlan, match.getDataLayerVirtualLan()); + assertEquals(pcp, + match.getDataLayerVirtualLanPriorityCodePoint()); + } + } + + // Set "dl_vpcp" field firstly, "dl_vlan" field secondly. + for (short vlan: vlans) { + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.fromString("dl_vpcp=" + pcp); + match.fromString("dl_vlan=" + vlan); + assertEquals(MATCH_LEN_VLAN_TCI, match.getIPv6MatchLen()); + assertEquals(vlan, match.getDataLayerVirtualLan()); + assertEquals(pcp, + match.getDataLayerVirtualLanPriorityCodePoint()); + } + } + + // Test for OFP_VLAN_NONE when VLAN PCP is not set. + V6Match match = new V6Match(); + match.fromString("dl_vlan=" + OFP_VLAN_NONE); + assertEquals(MATCH_LEN_VLAN_TCI, match.getIPv6MatchLen()); + assertEquals(OFP_VLAN_NONE, match.getDataLayerVirtualLan()); + + // Test for OFP_VLAN_NONE when VLAN PCP is set. + match = new V6Match(); + match.fromString("dl_vpcp=" + 1); + try { + match.fromString("dl_vlan=" + OFP_VLAN_NONE); + fail("Throwing exception was expected."); + } catch (IllegalArgumentException e) { + // Throwing exception was expected. + } + } + + /** + * Test case for {@link V6Match#writeTo(ByteBuffer)} for VLAN TCI field. + */ + @Test + public void testWriteToVlanTci() { + byte mask = 0; + + // Set only VLAN ID. + short vlans[] = {1, 10, 1000, 4095}; + for (short vlan: vlans) { + V6Match match = new V6Match(); + match.setDataLayerVirtualLan(vlan, mask); + ByteBuffer data = ByteBuffer.allocate(10); + match.writeTo(data); + assertEquals(MATCH_LEN_VLAN_TCI_WITH_MASK, data.position()); + data.flip(); + // Header + assertEquals(HEADER_VLAN_TCI_W, data.getInt()); + // Value + short expectedTci = (short) (VLAN_TCI_CFI | vlan); + assertEquals(expectedTci, data.getShort()); + // Mask + short expectedMask = 0x1fff; + assertEquals(expectedMask, data.getShort()); + } + + // Set only VLAN PCP. + byte pcps[] = {1, 3, 7}; + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.setDataLayerVirtualLanPriorityCodePoint(pcp, mask); + ByteBuffer data = ByteBuffer.allocate(10); + match.writeTo(data); + assertEquals(MATCH_LEN_VLAN_TCI_WITH_MASK, data.position()); + data.flip(); + // Header + assertEquals(HEADER_VLAN_TCI_W, data.getInt()); + // Value + short expectedTci = (short) (pcp << 13 | VLAN_TCI_CFI); + assertEquals(expectedTci, data.getShort()); + // Mask + short expectedMask = (short) 0xf000; + assertEquals(expectedMask, data.getShort()); + } + + // Set both VLAN ID and PCP. + for (short vlan: vlans) { + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.setDataLayerVirtualLan(vlan, mask); + match.setDataLayerVirtualLanPriorityCodePoint(pcp, mask); + ByteBuffer data = ByteBuffer.allocate(10); + match.writeTo(data); + assertEquals(MATCH_LEN_VLAN_TCI, data.position()); + data.flip(); + // Header + assertEquals(HEADER_VLAN_TCI, data.getInt()); + // Value + short expectedTci = (short) (pcp << 13 | VLAN_TCI_CFI | vlan); + assertEquals(expectedTci, data.getShort()); + } + } + + // Set OFP_VLAN_NONE. + V6Match match = new V6Match(); + match.setDataLayerVirtualLan(OFP_VLAN_NONE, mask); + ByteBuffer data = ByteBuffer.allocate(10); + match.writeTo(data); + assertEquals(MATCH_LEN_VLAN_TCI, data.position()); + data.flip(); + // Header + assertEquals(HEADER_VLAN_TCI, data.getInt()); + // Value + assertEquals(0, data.getShort()); + } + + /** + * Test case for {@link V6Match#writeTo(ByteBuffer)} for input port field. + */ + @Test + public void testWriteToInputPort() { + // Set input port. + short ports[] = {1, 10, 100, 1000}; + for (short port: ports) { + V6Match match = new V6Match(); + match.setInputPort(port, (short) 0); + ByteBuffer data = ByteBuffer.allocate(10); + match.writeTo(data); + assertEquals(MATCH_LEN_INPUT_PORT, data.position()); + data.flip(); + // Header + assertEquals(HEADER_INPUT_PORT, data.getInt()); + // Value + assertEquals(port, data.getShort()); + } + } + + /** + * Test case for {@link V6Match#readFrom(ByteBuffer)} for VLAN TCI field. + */ + @Test + public void testReadFromVlanTci() { + // Test for an exact match a TCI value with CFI=1. + // It matches packets that have an 802.1Q header with a specified + // VID and PCP. + short vlans[] = {1, 10, 1000, 4095}; + byte pcps[] = {1, 3, 7}; + for (short vlan: vlans) { + for (byte pcp: pcps) { + ByteBuffer data = ByteBuffer.allocate(MATCH_LEN_VLAN_TCI); + data.putInt(HEADER_VLAN_TCI); + short tci = (short) (pcp << 13 | VLAN_TCI_CFI | vlan); + data.putShort(tci); + data.flip(); + + V6Match match = new V6Match(); + match.readFrom(data); + assertEquals(MATCH_LEN_VLAN_TCI, match.getIPv6MatchLen()); + assertEquals(pcp, + match.getDataLayerVirtualLanPriorityCodePoint()); + assertEquals(vlan, match.getDataLayerVirtualLan()); + int wildcards = OFPFW_ALL & ~OFPFW_DL_VLAN_PCP & ~OFPFW_DL_VLAN; + assertEquals(wildcards, match.getWildcards()); + } + } + + // Test with a specific VID and CFI=1 with mask=0x1fff. + // It matches packets that have an 802.1Q header with that VID + // and any PCP. + for (short vlan: vlans) { + ByteBuffer data = ByteBuffer.allocate(MATCH_LEN_VLAN_TCI_WITH_MASK); + data.putInt(HEADER_VLAN_TCI_W); + short tci = (short) (VLAN_TCI_CFI | vlan); + data.putShort(tci); + short mask = (short) 0x1fff; + data.putShort(mask); + data.flip(); + + V6Match match = new V6Match(); + match.readFrom(data); + assertEquals(MATCH_LEN_VLAN_TCI_WITH_MASK, match.getIPv6MatchLen()); + assertEquals(vlan, match.getDataLayerVirtualLan()); + int wildcards = OFPFW_ALL & ~OFPFW_DL_VLAN; + assertEquals(wildcards, match.getWildcards()); + } + + // Test with a specific PCP and CFI=1 with mask=0xf000. + // It matches packets that have an 802.1Q header with that PCP + // and any VID. + for (byte pcp: pcps) { + ByteBuffer data = ByteBuffer.allocate(MATCH_LEN_VLAN_TCI_WITH_MASK); + data.putInt(HEADER_VLAN_TCI_W); + short tci = (short) (pcp << 13| VLAN_TCI_CFI); + data.putShort(tci); + short mask = (short) 0xf000; + data.putShort(mask); + data.flip(); + + V6Match match = new V6Match(); + match.readFrom(data); + assertEquals(MATCH_LEN_VLAN_TCI_WITH_MASK, match.getIPv6MatchLen()); + assertEquals(pcp, match.getDataLayerVirtualLanPriorityCodePoint()); + int wildcards = OFPFW_ALL & ~OFPFW_DL_VLAN_PCP; + assertEquals(wildcards, match.getWildcards()); + } + + // Test for an exact match with 0. + // It matches only packets without an 802.1Q header. + ByteBuffer data = ByteBuffer.allocate(MATCH_LEN_VLAN_TCI); + data.putInt(HEADER_VLAN_TCI); + short tci = 0; + data.putShort(tci); + data.flip(); + + V6Match match = new V6Match(); + match.readFrom(data); + assertEquals(MATCH_LEN_VLAN_TCI, match.getIPv6MatchLen()); + assertEquals(OFP_VLAN_NONE, match.getDataLayerVirtualLan()); + int wildcards = OFPFW_ALL & ~OFPFW_DL_VLAN; + assertEquals(wildcards, match.getWildcards()); + } + + /** + * Test case for {@link V6Match#readFrom(ByteBuffer)} for input port field. + */ + @Test + public void testReadFromInputPort() { + // Set input port. + short ports[] = {1, 10, 100, 1000}; + for (short port: ports) { + ByteBuffer data = ByteBuffer.allocate(MATCH_LEN_INPUT_PORT); + data.putInt(HEADER_INPUT_PORT); + data.putShort(port); + data.flip(); + + V6Match match = new V6Match(); + match.readFrom(data); + assertEquals(MATCH_LEN_INPUT_PORT, match.getIPv6MatchLen()); + assertEquals(port, match.getInputPort()); + int wildcards = OFPFW_ALL & ~OFPFW_IN_PORT; + assertEquals(wildcards, match.getWildcards()); + } + } + + /** + * Test case for {@link V6Match#setDataLayerVirtualLan(short, short)}. + */ + @Test + public void testSetDataLayerVirtualLan() { + short vlans[] = {1, 10, 1000, 4095}; + short mask = 0; + for (short vlan: vlans) { + V6Match match = new V6Match(); + match.setDataLayerVirtualLan(vlan, mask); + assertEquals(MATCH_LEN_VLAN_TCI_WITH_MASK, match.getIPv6MatchLen()); + assertEquals(vlan, match.getDataLayerVirtualLan()); + } + + // Test for OFP_VLAN_NONE. + V6Match match = new V6Match(); + match.setDataLayerVirtualLan(OFP_VLAN_NONE, mask); + assertEquals(MATCH_LEN_VLAN_TCI, match.getIPv6MatchLen()); + assertEquals(OFP_VLAN_NONE, match.getDataLayerVirtualLan()); + } + + /** + * Test case for + * {@link V6Match#setDataLayerVirtualLanPriorityCodePoint(byte, byte)}. + */ + @Test + public void testSetDataLayerVirtualLanPriorityCodePoint() { + byte pcps[] = {1, 3, 7}; + byte mask = 0; + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.setDataLayerVirtualLanPriorityCodePoint(pcp, mask); + assertEquals(MATCH_LEN_VLAN_TCI_WITH_MASK, match.getIPv6MatchLen()); + assertEquals(pcp, match.getDataLayerVirtualLanPriorityCodePoint()); + } + } + + /** + * Test case for setter methods for VLAN TCI field. + * + * This test case calls {@link V6Match#setDataLayerVirtualLan(short, short)} + * and {@link V6Match#setDataLayerVirtualLanPriorityCodePoint(byte, byte)}. + */ + @Test + public void testSetVlanTCI() { + short vlans[] = {1, 10, 1000, 4095}; + byte pcps[] = {1, 3, 7}; + byte mask = 0; + + // Call setDataLayerVirtualLan(short, short) firstly, + // and setDataLayerVirtualLanPriorityCodePoint(byte, byte) secondly, + for (short vlan: vlans) { + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.setDataLayerVirtualLan(vlan, mask); + match.setDataLayerVirtualLanPriorityCodePoint(pcp, mask); + assertEquals(MATCH_LEN_VLAN_TCI, match.getIPv6MatchLen()); + assertEquals(vlan, match.getDataLayerVirtualLan()); + assertEquals(pcp, + match.getDataLayerVirtualLanPriorityCodePoint()); + } + } + + // Call setDataLayerVirtualLanPriorityCodePoint(byte, byte) firstly, + // and setDataLayerVirtualLan(short, short) secondly. + for (short vlan: vlans) { + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.setDataLayerVirtualLanPriorityCodePoint(pcp, mask); + match.setDataLayerVirtualLan(vlan, mask); + assertEquals(MATCH_LEN_VLAN_TCI, match.getIPv6MatchLen()); + assertEquals(vlan, match.getDataLayerVirtualLan()); + assertEquals(pcp, + match.getDataLayerVirtualLanPriorityCodePoint()); + } + } + + // Test for setting OFP_VLAN_NONE when VLAN PCP is set. + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.setDataLayerVirtualLanPriorityCodePoint(pcp, mask); + try { + match.setDataLayerVirtualLan(OFP_VLAN_NONE, mask); + } catch (IllegalStateException e) { + // Throwing exception was expected. + } + } + + // Test for set VLAN PCP when OFP_VLAN_NONE is set to VLAN match. + for (byte pcp: pcps) { + V6Match match = new V6Match(); + match.setDataLayerVirtualLan(OFP_VLAN_NONE, mask); + try { + match.setDataLayerVirtualLanPriorityCodePoint(pcp, mask); + } catch (IllegalStateException e) { + // Throwing exception was expected. + } + } + } + + /** + * Test case for {@link V6Match#setInputPort(short, short)}. + */ + @Test + public void testSetInputPort() { + short ports[] = {1, 10, 100, 1000}; + for (short port: ports) { + V6Match match = new V6Match(); + match.setInputPort(port, (short) 0); + assertEquals(MATCH_LEN_INPUT_PORT, match.getIPv6MatchLen()); + assertEquals(port, match.getInputPort()); + } + } +} -- 2.36.6