X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fprotocol_plugins%2Fopenflow%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fprotocol_plugin%2Fopenflow%2Fvendorextension%2Fv6extension%2FV6Match.java;h=4b8966c54698b048490480aa5f758cf1d1df1e2b;hp=2da6b9b00891008850075e31920d02c01888ad16;hb=5135f2d97f0886632f3ad3b7160a3be54909810f;hpb=3017ec571b85a1190f157939d17de03f43ccf5cf 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 2da6b9b008..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,6 +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, @@ -9,49 +8,44 @@ package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension; -import org.apache.commons.lang3.builder.ReflectionToStringBuilder; -import org.openflow.protocol.OFMatch; -import org.openflow.util.U16; -import org.openflow.util.U8; - import java.net.Inet6Address; -import org.opendaylight.controller.sal.utils.HexEncode; - import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; +import java.util.Arrays; +import org.opendaylight.controller.sal.utils.HexEncode; +import org.opendaylight.controller.sal.utils.NetUtils; +import org.openflow.protocol.OFMatch; +import org.openflow.util.U16; +import org.openflow.util.U8; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This Class forms the vendor specific IPv6 Flow Match messages as well as * processes the vendor specific IPv6 Stats Reply message. - * - * For message creation, it parses the user entered IPv6 match fields, creates - * a sub-message for each field which are later used to form the complete - * message. - * + * + * For message creation, it parses the user entered IPv6 match fields, creates a + * sub-message for each field which are later used to form the complete message. + * * For message processing, it parses the incoming message and reads each field * of the message and stores in appropriate field of V6Match object. - * + * * */ public class V6Match extends OFMatch implements Cloneable { private static final Logger logger = LoggerFactory.getLogger(V6Match.class); private static final long serialVersionUID = 1L; - protected InetAddress nwSrc; - protected InetAddress nwDst; + protected Inet6Address nwSrc; + protected Inet6Address nwDst; protected short inputPortMask; protected byte[] dataLayerSourceMask; protected byte[] dataLayerDestinationMask; - protected short dataLayerVirtualLanMask; - protected byte dataLayerVirtualLanPriorityCodePointMask; + protected int dataLayerVirtualLanTCIMask; protected short dataLayerTypeMask; protected byte networkTypeOfServiceMask; protected byte networkProtocolMask; - protected InetAddress networkSourceMask; - protected InetAddress networkDestinationMask; protected short transportSourceMask; protected short transportDestinationMask; protected short srcIPv6SubnetMaskbits; @@ -60,7 +54,9 @@ public class V6Match extends OFMatch implements Cloneable { protected MatchFieldState inputPortState; protected MatchFieldState dlSourceState; protected MatchFieldState dlDestState; - protected MatchFieldState dlVlanState; + protected MatchFieldState dlVlanIDState; + protected MatchFieldState dlVlanPCPState; + protected MatchFieldState dlVlanTCIState; protected MatchFieldState ethTypeState; protected MatchFieldState nwTosState; protected MatchFieldState nwProtoState; @@ -73,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 } @@ -134,10 +140,7 @@ public class V6Match extends OFMatch implements Cloneable { this.dataLayerSourceMask = null; this.dataLayerDestinationMask = null; this.dataLayerTypeMask = 0; - this.dataLayerVirtualLanMask = 0; - this.dataLayerVirtualLanPriorityCodePointMask = 0; - this.networkDestinationMask = null; - this.networkSourceMask = null; + this.dataLayerVirtualLanTCIMask = 0; this.networkTypeOfServiceMask = 0; this.networkProtocolMask = 0; this.transportSourceMask = 0; @@ -146,7 +149,9 @@ public class V6Match extends OFMatch implements Cloneable { this.inputPortState = MatchFieldState.MATCH_ABSENT; this.dlSourceState = MatchFieldState.MATCH_ABSENT; this.dlDestState = MatchFieldState.MATCH_ABSENT; - this.dlVlanState = MatchFieldState.MATCH_ABSENT; + this.dlVlanIDState = MatchFieldState.MATCH_ABSENT; + this.dlVlanPCPState = MatchFieldState.MATCH_ABSENT; + this.dlVlanTCIState = MatchFieldState.MATCH_ABSENT; this.ethTypeState = MatchFieldState.MATCH_ABSENT; this.nwTosState = MatchFieldState.MATCH_ABSENT; this.nwProtoState = MatchFieldState.MATCH_ABSENT; @@ -164,33 +169,19 @@ public class V6Match extends OFMatch implements Cloneable { this.match_len = 0; this.pad_size = 0; - this.networkSourceMask = null; if (match.getNetworkSource() != 0) { - InetAddress address = null; - try { - address = InetAddress.getByAddress(ByteBuffer.allocate(4) - .putInt(match.getNetworkSource()).array()); - } catch (UnknownHostException e) { - logger.error("",e); - } - this.setNetworkSource(address, null); + InetAddress address = NetUtils.getInetAddress(match.getNetworkSource()); + InetAddress mask = NetUtils.getInetNetworkMask(match.getNetworkSourceMaskLen(), false); + this.setNetworkSource(address, mask); } else { - this.nwSrc = null; this.nwSrcState = MatchFieldState.MATCH_ABSENT; } - this.networkDestinationMask = null; if (match.getNetworkDestination() != 0) { - InetAddress address = null; - try { - address = InetAddress.getByAddress(ByteBuffer.allocate(4) - .putInt(match.getNetworkDestination()).array()); - } catch (UnknownHostException e) { - logger.error("",e); - } - this.setNetworkDestination(address, null); + InetAddress address = NetUtils.getInetAddress(match.getNetworkDestination()); + InetAddress mask = NetUtils.getInetNetworkMask(match.getNetworkDestinationMaskLen(), false); + this.setNetworkDestination(address, mask); } else { - this.nwDst = null; this.nwDstState = MatchFieldState.MATCH_ABSENT; } @@ -203,17 +194,17 @@ public class V6Match extends OFMatch implements Cloneable { } this.dataLayerSourceMask = null; - if (match.getDataLayerSource() != null) { + if (match.getDataLayerSource() != null + && !NetUtils.isZeroMAC(match.getDataLayerSource())) { this.setDataLayerSource(match.getDataLayerSource(), null); } else { - this.dataLayerSource = null; this.dlSourceState = MatchFieldState.MATCH_ABSENT; } this.dataLayerDestinationMask = null; - if (match.getDataLayerDestination() != null) { + if (match.getDataLayerDestination() != null + && !NetUtils.isZeroMAC(match.getDataLayerDestination())) { this.setDataLayerDestination(match.getDataLayerDestination(), null); } else { - this.dataLayerDestination = null; this.dlDestState = MatchFieldState.MATCH_ABSENT; } @@ -225,27 +216,28 @@ public class V6Match extends OFMatch implements Cloneable { this.ethTypeState = MatchFieldState.MATCH_ABSENT; } - this.dataLayerVirtualLanMask = 0; + this.dataLayerVirtualLanTCIMask = 0; + this.dlVlanTCIState = MatchFieldState.MATCH_ABSENT; if (match.getDataLayerVirtualLan() != 0) { this.setDataLayerVirtualLan(match.getDataLayerVirtualLan(), (short) 0); } else { this.dataLayerVirtualLan = 0; - this.dlVlanState = MatchFieldState.MATCH_ABSENT; + this.dlVlanIDState = MatchFieldState.MATCH_ABSENT; } - this.dataLayerVirtualLanPriorityCodePointMask = 0; - if (match.getDataLayerVirtualLanPriorityCodePoint() != 0) { - this.setDataLayerVirtualLanPriorityCodePoint(match - .getDataLayerVirtualLanPriorityCodePoint(), (byte) 0); + if ((match.getWildcards() & OFMatch.OFPFW_DL_VLAN_PCP) == 0) { + this.setDataLayerVirtualLanPriorityCodePoint( + match.getDataLayerVirtualLanPriorityCodePoint(), (byte) 0); } else { this.dataLayerVirtualLanPriorityCodePoint = 0; + this.dlVlanPCPState = MatchFieldState.MATCH_ABSENT; } this.networkProtocolMask = 0; if (match.getNetworkProtocol() != 0) { - this.setNetworkProtocol(this.networkProtocol = match - .getNetworkProtocol(), (byte) 0); + this.setNetworkProtocol( + this.networkProtocol = match.getNetworkProtocol(), (byte) 0); } else { this.networkProtocol = 0; this.nwProtoState = MatchFieldState.MATCH_ABSENT; @@ -253,8 +245,9 @@ public class V6Match extends OFMatch implements Cloneable { this.networkTypeOfServiceMask = 0; if (match.getNetworkTypeOfService() != 0) { - this.setNetworkTypeOfService(this.networkTypeOfService = match - .getNetworkTypeOfService(), (byte) 0); + this.setNetworkTypeOfService( + this.networkTypeOfService = match.getNetworkTypeOfService(), + (byte) 0); } else { this.networkTypeOfService = match.getNetworkTypeOfService(); this.nwTosState = MatchFieldState.MATCH_ABSENT; @@ -348,13 +341,51 @@ public class V6Match extends OFMatch implements Cloneable { return (ipv6ext_etype_msg.array()); } - private byte[] getIPv6ExtensionVlanIDMatchMsg(short VLAN) { - ByteBuffer ipv6ext_vlanid_msg = ByteBuffer.allocate(6); + private byte[] getVlanTCI(short dataLayerVirtualLanID, + byte dataLayerVirtualLanPriorityCodePoint) { + ByteBuffer vlan_tci = ByteBuffer.allocate(2); + 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(); + } + + private byte[] getIPv6ExtensionVlanTCIMatchMsg(short dataLayerVirtualLanID, + byte dataLayerVirtualLanPriorityCodePoint) { + ByteBuffer ipv6ext_vlan_tci_msg = ByteBuffer.allocate(6); int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10, OF_Match_Types.MATCH_OF_VLAN_TCI.getValue(), 0, 2); - ipv6ext_vlanid_msg.putInt(nxm_header); - ipv6ext_vlanid_msg.putShort(VLAN); - return (ipv6ext_vlanid_msg.array()); + ipv6ext_vlan_tci_msg.putInt(nxm_header); + ipv6ext_vlan_tci_msg.put(getVlanTCI(dataLayerVirtualLanID, + dataLayerVirtualLanPriorityCodePoint)); + return (ipv6ext_vlan_tci_msg.array()); + } + + private byte[] getIPv6ExtensionVlanTCIMatchWithMaskMsg( + short dataLayerVirtualLan, + byte dataLayerVirtualLanPriorityCodePoint, + int dataLayerVirtualLanTCIMask) { + ByteBuffer ipv6ext_vlan_tci_msg = ByteBuffer.allocate(8); + int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10, + OF_Match_Types.MATCH_OF_VLAN_TCI.getValue(), 1, 4); + ipv6ext_vlan_tci_msg.putInt(nxm_header); + ipv6ext_vlan_tci_msg.put(getVlanTCI(dataLayerVirtualLan, + dataLayerVirtualLanPriorityCodePoint)); + ipv6ext_vlan_tci_msg.put((byte) (dataLayerVirtualLanTCIMask >> 8)); // bits + // 8 + // to + // 15 + ipv6ext_vlan_tci_msg.put((byte) (dataLayerVirtualLanTCIMask)); // bits 0 + // to 7 + return (ipv6ext_vlan_tci_msg.array()); } private byte[] getIPv6ExtensionSrcIPv6MatchMsg(byte[] srcIpv6) { @@ -413,11 +444,10 @@ public class V6Match extends OFMatch implements Cloneable { ipv6ext_proto_msg.putInt(nxm_header); if (protocol == IPProtocols.ICMP.getValue()) { /* - * The front end passes the same protocol type values for IPv4 - * and IPv6 flows. For the Protocol types we allow in our GUI - * (ICMP, TCP, UDP), ICMP is the only one which is different for - * IPv6. It is 1 for v4 and 58 for v6 Therefore, we overwrite it - * here. + * The front end passes the same protocol type values for IPv4 and + * IPv6 flows. For the Protocol types we allow in our GUI (ICMP, + * TCP, UDP), ICMP is the only one which is different for IPv6. It + * is 1 for v4 and 58 for v6 Therefore, we overwrite it here. */ protocol = IPProtocols.ICMPV6.getValue(); } @@ -471,27 +501,32 @@ public class V6Match extends OFMatch implements Cloneable { } /** - * Sets this (V6Match) object's member variables based on a comma-separated key=value pair similar to OFMatch's fromString. - * - * @param match a key=value comma separated string. + * Sets this (V6Match) object's member variables based on a comma-separated + * key=value pair similar to OFMatch's fromString. + * + * @param match + * a key=value comma separated string. */ @Override public void fromString(String match) throws IllegalArgumentException { if (match.equals("") || match.equalsIgnoreCase("any") - || match.equalsIgnoreCase("all") || match.equals("[]")) + || match.equalsIgnoreCase("all") || match.equals("[]")) { match = "OFMatch[]"; + } String[] tokens = match.split("[\\[,\\]]"); String[] values; int initArg = 0; - if (tokens[0].equals("OFMatch")) + if (tokens[0].equals("OFMatch")) { initArg = 1; + } this.wildcards = OFPFW_ALL; int i; for (i = initArg; i < tokens.length; i++) { values = tokens[i].split("="); - if (values.length != 2) + if (values.length != 2) { throw new IllegalArgumentException("Token " + tokens[i] + " does not have form 'key=value' parsing " + match); + } values[0] = values[0].toLowerCase(); // try to make this case insens if (values[0].equals(STR_IN_PORT) || values[0].equals("input_port")) { this.inputPort = U16.t(Integer.valueOf(values[1])); @@ -511,56 +546,96 @@ public class V6Match extends OFMatch implements Cloneable { this.wildcards &= ~OFPFW_DL_SRC; } else if (values[0].equals(STR_DL_TYPE) || values[0].equals("eth_type")) { - if (values[1].startsWith("0x")) + if (values[1].startsWith("0x")) { this.dataLayerType = U16.t(Integer.valueOf(values[1] .replaceFirst("0x", ""), 16)); - else + } else { + this.dataLayerType = U16.t(Integer.valueOf(values[1])); + } ethTypeState = MatchFieldState.MATCH_FIELD_ONLY; match_len += 6; } else if (values[0].equals(STR_DL_VLAN)) { - this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1])); - dlVlanState = MatchFieldState.MATCH_FIELD_ONLY; - match_len += 6; + 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 + // flag + // to check if the vlan id is being set so that we can set the + // dlVlanTCIState appropriately. + 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; + match_len += 8; + } + 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; + // the variable dlVlanPCPState is not really used as a flag + // for serializing and deserializing. Rather it is used as a + // flag + // to check if the vlan pcp is being set so that we can set the + // dlVlanTCIState appropriately. + if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT) { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; + match_len -= 2; + } else { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.dataLayerVirtualLanTCIMask = 0xf000; + match_len += 8; + } this.wildcards &= ~OFPFW_DL_VLAN_PCP; } else if (values[0].equals(STR_NW_DST) || values[0].equals("ip_dst")) { try { + InetAddress address = null; + InetAddress mask = null; if (values[1].contains("/")) { - String ipv6addr_wmask[] = values[1].split("/"); - this.nwDst = InetAddress.getByName(ipv6addr_wmask[0]); - this.dstIPv6SubnetMaskbits = Short - .valueOf(ipv6addr_wmask[1]); - nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK; - match_len += 36; + String addressString[] = values[1].split("/"); + address = InetAddress.getByName(addressString[0]); + int masklen = Integer.valueOf(addressString[1]); + mask = NetUtils.getInetNetworkMask(masklen, address instanceof Inet6Address); } else { - this.nwDst = InetAddress.getByName(values[1]); - nwDstState = MatchFieldState.MATCH_FIELD_ONLY; - match_len += 20; + address = InetAddress.getByName(values[1]); } + this.setNetworkDestination(address, mask); } catch (UnknownHostException e) { - logger.error("",e); + logger.error("", e); } } else if (values[0].equals(STR_NW_SRC) || values[0].equals("ip_src")) { try { + InetAddress address = null; + InetAddress mask = null; if (values[1].contains("/")) { - String ipv6addr_wmask[] = values[1].split("/"); - this.nwSrc = InetAddress.getByName(ipv6addr_wmask[0]); - this.srcIPv6SubnetMaskbits = Short - .valueOf(ipv6addr_wmask[1]); - nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK; - match_len += 36; + String addressString[] = values[1].split("/"); + address = InetAddress.getByName(addressString[0]); + int masklen = Integer.valueOf(addressString[1]); + mask = NetUtils.getInetNetworkMask(masklen, address instanceof Inet6Address); } else { - this.nwSrc = InetAddress.getByName(values[1]); - nwSrcState = MatchFieldState.MATCH_FIELD_ONLY; - match_len += 20; + address = InetAddress.getByName(values[1]); } + this.setNetworkSource(address, mask); } catch (UnknownHostException e) { - logger.error("",e); + logger.error("", e); } } else if (values[0].equals(STR_NW_PROTO)) { this.networkProtocol = U8.t(Short.valueOf(values[1])); @@ -583,14 +658,15 @@ public class V6Match extends OFMatch implements Cloneable { this.transportSource = U16.t(Integer.valueOf(values[1])); tpSrcState = MatchFieldState.MATCH_FIELD_ONLY; match_len += 6; - } else + } else { throw new IllegalArgumentException("unknown token " + tokens[i] + " parsing " + match); + } } /* - * In a V6 extension message action list should be preceded by a padding of 0 to - * 7 bytes based upon following formula. + * In a V6 extension message action list should be preceded by a padding + * of 0 to 7 bytes based upon following formula. */ pad_size = (short) (((match_len + 7) / 8) * 8 - match_len); @@ -620,9 +696,17 @@ public class V6Match extends OFMatch implements Cloneable { byte[] ipv6ext_srcmac_msg = getIPv6ExtensionSrcMacMatchMsg(this.dataLayerSource); data.put(ipv6ext_srcmac_msg); } - if (dlVlanState == MatchFieldState.MATCH_FIELD_ONLY) { - byte[] ipv6ext_vlan_id_msg = getIPv6ExtensionVlanIDMatchMsg(this.dataLayerVirtualLan); - data.put(ipv6ext_vlan_id_msg); + if (dlVlanTCIState == MatchFieldState.MATCH_FIELD_ONLY) { + byte[] ipv6ext_vlan_tci_msg = getIPv6ExtensionVlanTCIMatchMsg( + this.dataLayerVirtualLan, + this.dataLayerVirtualLanPriorityCodePoint); + data.put(ipv6ext_vlan_tci_msg); + } else if (dlVlanTCIState == MatchFieldState.MATCH_FIELD_WITH_MASK) { + byte[] ipv6ext_vlan_tci_msg_with_mask = getIPv6ExtensionVlanTCIMatchWithMaskMsg( + this.dataLayerVirtualLan, + this.dataLayerVirtualLanPriorityCodePoint, + this.dataLayerVirtualLanTCIMask); + data.put(ipv6ext_vlan_tci_msg_with_mask); } if (nwSrcState == MatchFieldState.MATCH_FIELD_ONLY) { byte[] ipv6ext_src_ipv6_msg = getIPv6ExtensionSrcIPv6MatchMsg(this.nwSrc @@ -678,11 +762,12 @@ public class V6Match extends OFMatch implements Cloneable { } private void readInPort(ByteBuffer data, int nxmLen, boolean hasMask) { - if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) + if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) { /* * mask is not allowed for inport port */ return; + } super.setInputPort(data.getShort()); this.inputPortState = MatchFieldState.MATCH_FIELD_ONLY; this.wildcards ^= (1 << 0); // Sync with 0F 1.0 Match @@ -692,9 +777,9 @@ public class V6Match extends OFMatch implements Cloneable { private void readDataLinkDestination(ByteBuffer data, int nxmLen, boolean hasMask) { if (hasMask) { - if ((nxmLen != 2 * 6) || (data.remaining() < 2 * 6)) + if ((nxmLen != 2 * 6) || (data.remaining() < 2 * 6)) { return; - else { + } else { byte[] bytes = new byte[6]; data.get(bytes); super.setDataLayerDestination(bytes); @@ -704,9 +789,9 @@ public class V6Match extends OFMatch implements Cloneable { this.match_len += 16; } } else { - if ((nxmLen != 6) || (data.remaining() < 6)) + if ((nxmLen != 6) || (data.remaining() < 6)) { return; - else { + } else { byte[] bytes = new byte[6]; data.get(bytes); super.setDataLayerDestination(bytes); @@ -721,8 +806,9 @@ public class V6Match extends OFMatch implements Cloneable { /* * mask is not allowed in data link source */ - if ((nxmLen != 6) || (data.remaining() < 6) || (hasMask)) + if ((nxmLen != 6) || (data.remaining() < 6) || (hasMask)) { return; + } byte[] bytes = new byte[6]; data.get(bytes); super.setDataLayerSource(bytes); @@ -735,49 +821,95 @@ public class V6Match extends OFMatch implements Cloneable { /* * mask is not allowed in ethertype */ - if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) + if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) { return; + } super.setDataLayerType(data.getShort()); this.ethTypeState = MatchFieldState.MATCH_FIELD_ONLY; this.wildcards ^= (1 << 4); // Sync with 0F 1.0 Match this.match_len += 6; } + private short getVlanID(byte firstByte, byte secondByte) { + short vlan_id_mask_firstByte = 0x0f;// this is the mask for the first + // byte + short vlan_id_mask_secondByte = 0xff;// this is the mask for the second + // byte + int vlanPart1 = (firstByte & vlan_id_mask_firstByte) << 8; + int vlanPart2 = secondByte & vlan_id_mask_secondByte; + return (short) (vlanPart1 + vlanPart2); + } + + private byte getVlanPCP(byte pcpByte) { + short vlan_pcp_mask = 0xe0;// this is the vlan pcp mask + int pcp_int = pcpByte & vlan_pcp_mask; + return (byte) (pcp_int >> 5); + } + private void readVlanTci(ByteBuffer data, int nxmLen, boolean hasMask) { - short vlan_mask = 0xfff; if (hasMask) { - if ((nxmLen != 2 * 2) || (data.remaining() < 2 * 2)) + if ((nxmLen != 2 * 2) || (data.remaining() < 2 * 2)) { return; + } else { - short vlan = data.getShort(); - vlan &= vlan_mask; - super.setDataLayerVirtualLan(vlan); - this.dataLayerVirtualLanMask = data.getShort(); - this.dlVlanState = MatchFieldState.MATCH_FIELD_WITH_MASK; + byte firstByte = data.get(); + byte secondByte = data.get(); + this.dataLayerVirtualLanTCIMask = data.getShort() & 0xffff; // we + // need + // the + // last + // 16 + // bits + // check the mask now + if ((this.dataLayerVirtualLanTCIMask & 0x0fff) != 0) { + // if its a vlan id mask + // extract the vlan id + super.setDataLayerVirtualLan(getVlanID(firstByte, + secondByte)); + this.wildcards ^= (1 << 1); // Sync with 0F 1.0 Match + } + if ((this.dataLayerVirtualLanTCIMask & 0xe000) != 0) { + // else if its a vlan pcp mask + // extract the vlan pcp + super.setDataLayerVirtualLanPriorityCodePoint(getVlanPCP(firstByte)); + this.wildcards ^= (1 << 20); + } + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; this.match_len += 8; - this.wildcards ^= (1 << 20); } } else { - if ((nxmLen != 2) || (data.remaining() < 2)) + if ((nxmLen != 2) || (data.remaining() < 2)) { return; + } else { - short vlan = data.getShort(); - vlan &= vlan_mask; - super.setDataLayerVirtualLan(vlan); - this.dlVlanState = MatchFieldState.MATCH_FIELD_ONLY; + // get the vlan pcp + byte firstByte = data.get(); + byte secondByte = data.get(); + 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 << 1); // Sync with 0F 1.0 Match } private void readIpTos(ByteBuffer data, int nxmLen, boolean hasMask) { /* * mask is not allowed in IP TOS */ - if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask)) + if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask)) { return; + } super.setNetworkTypeOfService(data.get()); this.nwTosState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 5; @@ -788,8 +920,9 @@ public class V6Match extends OFMatch implements Cloneable { /* * mask is not allowed in IP protocol */ - if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask)) + if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask)) { return; + } super.setNetworkProtocol(data.get()); this.nwProtoState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 5; @@ -798,87 +931,70 @@ public class V6Match extends OFMatch implements Cloneable { private void readIpv4Src(ByteBuffer data, int nxmLen, boolean hasMask) { if (hasMask) { - if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4)) + if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4)) { return; - else { + } else { byte[] sbytes = new byte[4]; data.get(sbytes); - try { - this.nwSrc = InetAddress.getByAddress(sbytes); - } catch (UnknownHostException e) { - return; - } + // For compatibility, let's set the IPv4 in the parent OFMatch + int address = NetUtils.byteArray4ToInt(sbytes); + super.setNetworkSource(address); byte[] mbytes = new byte[4]; data.get(mbytes); - try { - this.networkSourceMask = InetAddress.getByAddress(mbytes); - } catch (UnknownHostException e) { - return; - } this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK; this.match_len += 12; int prefixlen = getNetworkMaskPrefixLength(mbytes); this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0 Match this.wildcards |= ((32 - prefixlen) << 8); // Sync with 0F 1.0 Match - } } else { - if ((nxmLen != 4) || (data.remaining() < 4)) + if ((nxmLen != 4) || (data.remaining() < 4)) { return; - else { + } else { byte[] sbytes = new byte[4]; data.get(sbytes); - try { - this.nwSrc = InetAddress.getByAddress(sbytes); - } catch (UnknownHostException e) { - return; - } + // For compatibility, let's also set the IPv4 in the parent OFMatch + int address = NetUtils.byteArray4ToInt(sbytes); + super.setNetworkSource(address); this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 8; - this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0 Match + this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0 + // Match } } } private void readIpv4Dst(ByteBuffer data, int nxmLen, boolean hasMask) { if (hasMask) { - if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4)) + if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4)) { return; - else { + } else { byte[] dbytes = new byte[4]; data.get(dbytes); - try { - this.nwDst = InetAddress.getByAddress(dbytes); - } catch (UnknownHostException e) { - return; - } + // For compatibility, let's also set the IPv4 in the parent OFMatch + int address = NetUtils.byteArray4ToInt(dbytes); + super.setNetworkDestination(address); byte[] mbytes = new byte[4]; data.get(mbytes); - try { - this.networkDestinationMask = InetAddress - .getByAddress(mbytes); - } catch (UnknownHostException e) { - return; - } this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK; this.match_len += 12; int prefixlen = getNetworkMaskPrefixLength(mbytes); - this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 Match - this.wildcards |= ((32 - prefixlen) << 14); // Sync with 0F 1.0 Match + this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 + // Match + this.wildcards |= ((32 - prefixlen) << 14); // Sync with 0F 1.0 + // Match } } else { - if ((nxmLen != 4) || (data.remaining() < 4)) + if ((nxmLen != 4) || (data.remaining() < 4)) { return; - else { + } else { byte[] dbytes = new byte[4]; data.get(dbytes); - try { - this.nwDst = InetAddress.getByAddress(dbytes); - } catch (UnknownHostException e) { - return; - } + int address = NetUtils.byteArray4ToInt(dbytes); + super.setNetworkDestination(address); this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY; - this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 Match + this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 + // Match this.match_len += 8; } } @@ -888,8 +1004,9 @@ public class V6Match extends OFMatch implements Cloneable { /* * mask is not allowed in TCP SRC */ - if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) + if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) { return; + } super.setTransportSource(data.getShort()); this.tpSrcState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 6; @@ -900,8 +1017,9 @@ public class V6Match extends OFMatch implements Cloneable { /* * mask is not allowed in TCP DST */ - if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) + if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) { return; + } super.setTransportDestination(data.getShort()); this.tpDstState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 6; @@ -912,8 +1030,9 @@ public class V6Match extends OFMatch implements Cloneable { /* * mask is not allowed in UDP SRC */ - if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) + if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) { return; + } super.setTransportSource(data.getShort()); this.tpSrcState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 6; @@ -924,8 +1043,9 @@ public class V6Match extends OFMatch implements Cloneable { /* * mask is not allowed in UDP DST */ - if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) + if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask)) { return; + } super.setTransportDestination(data.getShort()); this.tpDstState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 6; @@ -934,34 +1054,30 @@ public class V6Match extends OFMatch implements Cloneable { private void readIpv6Src(ByteBuffer data, int nxmLen, boolean hasMask) { if (hasMask) { - if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16)) + if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16)) { return; - else { + } else { byte[] sbytes = new byte[16]; data.get(sbytes); try { - this.nwSrc = InetAddress.getByAddress(sbytes); + this.nwSrc = (Inet6Address) InetAddress.getByAddress(sbytes); } catch (UnknownHostException e) { return; } byte[] mbytes = new byte[16]; data.get(mbytes); - try { - this.networkSourceMask = InetAddress.getByAddress(mbytes); - } catch (UnknownHostException e) { - return; - } + this.srcIPv6SubnetMaskbits = (short)NetUtils.getSubnetMaskLength(mbytes); this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK; this.match_len += 36; } } else { - if ((nxmLen != 16) || (data.remaining() < 16)) + if ((nxmLen != 16) || (data.remaining() < 16)) { return; - else { + } else { byte[] sbytes = new byte[16]; data.get(sbytes); try { - this.nwSrc = InetAddress.getByAddress(sbytes); + this.nwSrc = (Inet6Address) InetAddress.getByAddress(sbytes); } catch (UnknownHostException e) { return; } @@ -973,35 +1089,30 @@ public class V6Match extends OFMatch implements Cloneable { private void readIpv6Dst(ByteBuffer data, int nxmLen, boolean hasMask) { if (hasMask) { - if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16)) + if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16)) { return; - else { + } else { byte[] dbytes = new byte[16]; data.get(dbytes); try { - this.nwDst = InetAddress.getByAddress(dbytes); + this.nwDst = (Inet6Address) InetAddress.getByAddress(dbytes); } catch (UnknownHostException e) { return; } byte[] mbytes = new byte[16]; data.get(mbytes); - try { - this.networkDestinationMask = InetAddress - .getByAddress(mbytes); - } catch (UnknownHostException e) { - return; - } + this.dstIPv6SubnetMaskbits = (short)NetUtils.getSubnetMaskLength(mbytes); this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK; this.match_len += 36; } } else { - if ((nxmLen != 16) || (data.remaining() < 16)) + if ((nxmLen != 16) || (data.remaining() < 16)) { return; - else { + } else { byte[] dbytes = new byte[16]; data.get(dbytes); try { - this.nwDst = InetAddress.getByAddress(dbytes); + this.nwDst = (Inet6Address) InetAddress.getByAddress(dbytes); } catch (UnknownHostException e) { return; } @@ -1013,13 +1124,34 @@ public class V6Match extends OFMatch implements Cloneable { @Override public String toString() { - return "V6Match[" + ReflectionToStringBuilder.toString(this) + "]"; + return "V6Match [nwSrc=" + nwSrc + ", nwDst=" + nwDst + + ", inputPortMask=" + inputPortMask + ", dataLayerSourceMask=" + + HexEncode.bytesToHexStringFormat(dataLayerSourceMask) + + ", dataLayerDestinationMask=" + + HexEncode.bytesToHexStringFormat(dataLayerDestinationMask) + + ", dataLayerVirtualLanTCIMask=" + dataLayerVirtualLanTCIMask + + ", dataLayerTypeMask=" + dataLayerTypeMask + + ", networkTypeOfServiceMask=" + networkTypeOfServiceMask + + ", networkProtocolMask=" + networkProtocolMask + + ", transportSourceMask=" + transportSourceMask + + ", transportDestinationMask=" + transportDestinationMask + + ", srcIPv6SubnetMaskbits=" + srcIPv6SubnetMaskbits + + ", dstIPv6SubnetMaskbits=" + dstIPv6SubnetMaskbits + + ", inputPortState=" + inputPortState + ", dlSourceState=" + + dlSourceState + ", dlDestState=" + dlDestState + + ", dlVlanTCIState=" + dlVlanTCIState + ", ethTypeState=" + + ethTypeState + ", nwTosState=" + nwTosState + + ", nwProtoState=" + nwProtoState + ", nwSrcState=" + + nwSrcState + ", nwDstState=" + nwDstState + ", tpSrcState=" + + tpSrcState + ", tpDstState=" + tpDstState + ", match_len=" + + match_len + ", pad_size=" + pad_size + "]"; } /** * Read the data corresponding to the match field (received from the wire) - * Input: data: match field(s). Since match field is of variable length, the whole data that are passed in - * are assumed to fem0tbd.be the match fields. + * Input: data: match field(s). Since match field is of variable length, the + * whole data that are passed in are assumed to fem0tbd.be the match fields. + * * @param data */ @Override @@ -1035,8 +1167,8 @@ public class V6Match extends OFMatch implements Cloneable { /* * at least 4 bytes for each match header */ - logger.error("Invalid Vendor Extension Header. Size {}", data - .remaining()); + logger.error("Invalid Vendor Extension Header. Size {}", + data.remaining()); return; } /* @@ -1112,15 +1244,13 @@ public class V6Match extends OFMatch implements Cloneable { // Sync with 0F 1.0 Match if (super.getDataLayerType() == 0x800) { if (((this.wildcards >> 8) & 0x3f) == 0x3f) { - //ipv4 src processing + // ipv4 src processing this.wildcards ^= (((1 << 5) - 1) << 8); } if (((this.wildcards >> 14) & 0x3f) == 0x3f) { - //ipv4 dest processing + // ipv4 dest processing this.wildcards ^= (((1 << 5) - 1) << 14); } - } else { - this.wildcards = 0; } } @@ -1130,10 +1260,10 @@ public class V6Match extends OFMatch implements Cloneable { V6Match ret = (V6Match) super.clone(); try { if (this.nwSrc != null) { - ret.nwSrc = InetAddress.getByAddress(this.nwSrc.getAddress()); + ret.nwSrc = (Inet6Address) InetAddress.getByAddress(this.nwSrc.getAddress()); } if (this.nwDst != null) { - ret.nwDst = InetAddress.getByAddress(this.nwDst.getAddress()); + ret.nwDst = (Inet6Address) InetAddress.getByAddress(this.nwDst.getAddress()); } return ret; } catch (UnknownHostException e) { @@ -1146,38 +1276,16 @@ public class V6Match extends OFMatch implements Cloneable { * * @return */ - - public InetAddress getNetworkDest() { + public Inet6Address getNetworkDest() { return this.nwDst; } - /** - * Get nw_src - * - * @return - */ - - public void setNetworkSrc(InetAddress address) { - nwSrc = address; - } - - /** - * Set nw_dst - * - * @return - */ - - public void setNetworkDest(InetAddress address) { - nwDst = address; - } - /** * Set nw_src * * @return */ - - public InetAddress getNetworkSrc() { + public Inet6Address getNetworkSrc() { return this.nwSrc; } @@ -1241,24 +1349,67 @@ public class V6Match extends OFMatch implements Cloneable { } } - public short getDataLayerVirtualLanMask() { - return dataLayerVirtualLanMask; - } - + /** + * 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; - if (mask == 0) { - this.dlVlanState = MatchFieldState.MATCH_FIELD_ONLY; - this.match_len += 6; + 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 flag + // to check if the vlan id is being set so that we can set the + // dlVlanTCIState appropriately. + 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.dataLayerVirtualLanMask = mask; - this.dlVlanState = MatchFieldState.MATCH_FIELD_WITH_MASK; - this.match_len += 8; + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.dataLayerVirtualLanTCIMask = 0x1fff; + match_len += 8; } } + /** + * 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; + // the variable dlVlanPCPState is not really used as a flag + // for serializing and deserializing. Rather it is used as a flag + // to check if the vlan pcp is being set so that we can set the + // dlVlanTCIState appropriately. + if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT) { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; + match_len -= 2; + } else { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.dataLayerVirtualLanTCIMask = 0xf000; + match_len += 8; + } } public void setDataLayerType(short ethType, short mask) { @@ -1282,35 +1433,63 @@ public class V6Match extends OFMatch implements Cloneable { this.match_len += 5; } - public InetAddress getNetworkSourceMask() { - return networkSourceMask; + public Inet6Address getNetworkSourceMask() { + return (this.nwSrcState == MatchFieldState.MATCH_FIELD_WITH_MASK) ? (Inet6Address) NetUtils.getInetNetworkMask( + this.srcIPv6SubnetMaskbits, true) : null; } public void setNetworkSource(InetAddress address, InetAddress mask) { - this.nwSrc = address; - if (mask == null) { - this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY; - this.match_len += (address instanceof Inet6Address) ? 20 : 8; + if (address instanceof Inet6Address) { + this.nwSrc = (Inet6Address) address; + if (mask == null) { + this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY; + this.match_len += (address instanceof Inet6Address) ? 20 : 8; + } else { + this.srcIPv6SubnetMaskbits = (short)NetUtils.getSubnetMaskLength(mask); + this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.match_len += (address instanceof Inet6Address) ? 36 : 12; + } } else { - this.networkSourceMask = mask; - this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK; - this.match_len += (address instanceof Inet6Address) ? 36 : 12; + super.setNetworkSource(NetUtils.byteArray4ToInt(address.getAddress())); + this.wildcards ^= (((1 << 6) - 1) << 8); + if (mask == null) { + this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY; + this.match_len += 8; + } else { + this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.match_len += 12; + this.wildcards |= ((32 - NetUtils.getSubnetMaskLength(mask)) << 8); + } } } - public InetAddress getNetworkDestinationMask() { - return networkDestinationMask; + public Inet6Address getNetworkDestinationMask() { + return (this.nwDstState == MatchFieldState.MATCH_FIELD_WITH_MASK) ? (Inet6Address) NetUtils.getInetNetworkMask( + this.dstIPv6SubnetMaskbits, true) : null; } public void setNetworkDestination(InetAddress address, InetAddress mask) { - this.nwDst = address; - if (mask == null) { - this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY; - this.match_len += (address instanceof Inet6Address) ? 20 : 8; + if (address instanceof Inet6Address) { + this.nwDst = (Inet6Address) address; + if (mask == null) { + this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY; + this.match_len += (address instanceof Inet6Address) ? 20 : 8; + } else { + this.dstIPv6SubnetMaskbits = (short)NetUtils.getSubnetMaskLength(mask); + this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.match_len += (address instanceof Inet6Address) ? 36 : 12; + } } else { - this.networkDestinationMask = mask; - this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK; - this.match_len += (address instanceof Inet6Address) ? 36 : 12; + this.setNetworkDestination(NetUtils.byteArray4ToInt(address.getAddress())); + this.wildcards ^= (((1 << 6) - 1) << 14); + if (mask == null) { + this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY; + this.match_len += 8; + } else { + this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.match_len += 12; + this.wildcards |= ((32 - NetUtils.getSubnetMaskLength(mask)) << 14); + } } } @@ -1348,4 +1527,146 @@ public class V6Match extends OFMatch implements Cloneable { } return nbytes; } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + Arrays.hashCode(dataLayerDestinationMask); + result = prime * result + Arrays.hashCode(dataLayerSourceMask); + result = prime * result + dataLayerTypeMask; + result = prime * result + dataLayerVirtualLanTCIMask; + result = prime * result + + ((dlDestState == null) ? 0 : dlDestState.hashCode()); + result = prime * result + + ((dlSourceState == null) ? 0 : dlSourceState.hashCode()); + result = prime * result + + ((dlVlanTCIState == null) ? 0 : dlVlanTCIState.hashCode()); + result = prime * result + dstIPv6SubnetMaskbits; + result = prime * result + + ((ethTypeState == null) ? 0 : ethTypeState.hashCode()); + result = prime * result + inputPortMask; + result = prime * result + + ((inputPortState == null) ? 0 : inputPortState.hashCode()); + result = prime * result + match_len; + result = prime * result + networkProtocolMask; + result = prime * result + networkTypeOfServiceMask; + result = prime * result + ((nwDst == null) ? 0 : nwDst.hashCode()); + result = prime * result + + ((nwDstState == null) ? 0 : nwDstState.hashCode()); + result = prime * result + + ((nwProtoState == null) ? 0 : nwProtoState.hashCode()); + result = prime * result + ((nwSrc == null) ? 0 : nwSrc.hashCode()); + result = prime * result + + ((nwSrcState == null) ? 0 : nwSrcState.hashCode()); + result = prime * result + + ((nwTosState == null) ? 0 : nwTosState.hashCode()); + result = prime * result + pad_size; + result = prime * result + srcIPv6SubnetMaskbits; + result = prime * result + + ((tpDstState == null) ? 0 : tpDstState.hashCode()); + result = prime * result + + ((tpSrcState == null) ? 0 : tpSrcState.hashCode()); + result = prime * result + transportDestinationMask; + result = prime * result + transportSourceMask; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + V6Match other = (V6Match) obj; + if (!Arrays.equals(dataLayerDestinationMask, other.dataLayerDestinationMask)) { + return false; + } + if (!Arrays.equals(dataLayerSourceMask, other.dataLayerSourceMask)) { + return false; + } + if (dataLayerTypeMask != other.dataLayerTypeMask) { + return false; + } + if (dataLayerVirtualLanTCIMask != other.dataLayerVirtualLanTCIMask) { + return false; + } + if (dlVlanTCIState != other.dlVlanTCIState) { + return false; + } + if (dlSourceState != other.dlSourceState) { + return false; + } + if (dstIPv6SubnetMaskbits != other.dstIPv6SubnetMaskbits) { + return false; + } + if (ethTypeState != other.ethTypeState) { + return false; + } + if (inputPortMask != other.inputPortMask) { + return false; + } + if (inputPortState != other.inputPortState) { + return false; + } + if (match_len != other.match_len) { + return false; + } + if (networkProtocolMask != other.networkProtocolMask) { + return false; + } + if (networkTypeOfServiceMask != other.networkTypeOfServiceMask) { + return false; + } + if (nwDst == null) { + if (other.nwDst != null) { + return false; + } + } else if (!nwDst.equals(other.nwDst)) { + return false; + } + if (nwDstState != other.nwDstState) { + return false; + } + if (nwProtoState != other.nwProtoState) { + return false; + } + if (nwSrc == null) { + if (other.nwSrc != null) { + return false; + } + } else if (!nwSrc.equals(other.nwSrc)) { + return false; + } + if (nwSrcState != other.nwSrcState) { + return false; + } + if (nwTosState != other.nwTosState) { + return false; + } + if (pad_size != other.pad_size) { + return false; + } + if (srcIPv6SubnetMaskbits != other.srcIPv6SubnetMaskbits) { + return false; + } + if (tpDstState != other.tpDstState) { + return false; + } + if (tpSrcState != other.tpSrcState) { + return false; + } + if (transportDestinationMask != other.transportDestinationMask) { + return false; + } + if (transportSourceMask != other.transportSourceMask) { + return false; + } + return true; + } }