From 24b34553e5687f4bb929353f9f697e6ecbfc0f0b Mon Sep 17 00:00:00 2001 From: Rob Vaterlaus <rob.vaterlaus@bigswitch.com> Date: Wed, 15 Feb 2012 16:51:53 -0800 Subject: [PATCH] Support for parsing the vendor data associated with OFVendor messages. Support for the role request/reply vendor extensions used in OVS. --- .../java/org/openflow/protocol/OFError.java | 36 +++- .../java/org/openflow/protocol/OFVendor.java | 68 ++++--- .../protocol/factory/BasicFactory.java | 47 ++++- .../protocol/factory/OFVendorDataFactory.java | 69 +++++++ .../factory/OFVendorDataFactoryAware.java | 28 +++ .../vendor/OFBasicVendorDataType.java | 71 +++++++ .../protocol/vendor/OFBasicVendorId.java | 162 ++++++++++++++++ .../vendor/OFByteArrayVendorData.java | 94 +++++++++ .../protocol/vendor/OFVendorData.java | 44 +++++ .../protocol/vendor/OFVendorDataType.java | 79 ++++++++ .../openflow/protocol/vendor/OFVendorId.java | 85 ++++++++ .../vendor/nicira/OFNiciraVendorData.java | 97 ++++++++++ .../vendor/nicira/OFRoleReplyVendorData.java | 66 +++++++ .../nicira/OFRoleRequestVendorData.java | 66 +++++++ .../vendor/nicira/OFRoleVendorData.java | 113 +++++++++++ .../org/openflow/protocol/OFErrorTest.java | 6 +- .../org/openflow/protocol/OFVendorTest.java | 183 +++++++++++++++++- 17 files changed, 1278 insertions(+), 36 deletions(-) create mode 100644 src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java create mode 100644 src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java create mode 100644 src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java create mode 100644 src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java create mode 100644 src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java create mode 100644 src/main/java/org/openflow/protocol/vendor/OFVendorData.java create mode 100644 src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java create mode 100644 src/main/java/org/openflow/protocol/vendor/OFVendorId.java create mode 100644 src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java create mode 100644 src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java create mode 100644 src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java create mode 100644 src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java diff --git a/src/main/java/org/openflow/protocol/OFError.java b/src/main/java/org/openflow/protocol/OFError.java index 9cddce6de..4dccfe47e 100644 --- a/src/main/java/org/openflow/protocol/OFError.java +++ b/src/main/java/org/openflow/protocol/OFError.java @@ -35,7 +35,27 @@ public class OFError extends OFMessage implements OFMessageFactoryAware { public static int MINIMUM_LENGTH = 12; public enum OFErrorType { - OFPET_HELLO_FAILED, OFPET_BAD_REQUEST, OFPET_BAD_ACTION, OFPET_FLOW_MOD_FAILED, OFPET_PORT_MOD_FAILED, OFPET_QUEUE_OP_FAILED + // OFPET_VENDOR_ERROR is an extension that was added in Open vSwitch and isn't + // in the OF 1.0 spec, but it was easier to add it here instead of adding + // generic support for extensible vendor-defined error messages. + // It uses the random value 0xb0c2 to avoid conflicts with other possible new + // error types. Support for vendor-defined extended errors has been standardized + // in the OF 1.2 spec, so this workaround in only needed for 1.0. + OFPET_HELLO_FAILED, OFPET_BAD_REQUEST, OFPET_BAD_ACTION, OFPET_FLOW_MOD_FAILED, OFPET_PORT_MOD_FAILED, OFPET_QUEUE_OP_FAILED, OFPET_VENDOR_ERROR((short)0xb0c2); + + protected short value; + + private OFErrorType() { + this.value = (short) this.ordinal(); + } + + private OFErrorType(short value) { + this.value = value; + } + + public short getValue() { + return value; + } } public enum OFHelloFailedCode { @@ -64,6 +84,9 @@ public class OFError extends OFMessage implements OFMessageFactoryAware { protected short errorType; protected short errorCode; + protected int vendor; + protected int vendorErrorType; + protected short vendorErrorCode; protected OFMessageFactory factory; protected byte[] error; protected boolean errorIsAscii; @@ -90,9 +113,16 @@ public class OFError extends OFMessage implements OFMessageFactoryAware { } public void setErrorType(OFErrorType type) { - this.errorType = (short) type.ordinal(); + this.errorType = type.getValue(); } + /** + * @return true if the error is an extended vendor error + */ + public boolean isVendorError() { + return errorType == OFErrorType.OFPET_VENDOR_ERROR.getValue(); + } + /** * @return the errorCode */ @@ -210,7 +240,7 @@ public class OFError extends OFMessage implements OFMessageFactoryAware { if (dataLength > 0) { this.error = new byte[dataLength]; data.readBytes(this.error); - if (this.errorType == OFErrorType.OFPET_HELLO_FAILED.ordinal()) + if (this.errorType == OFErrorType.OFPET_HELLO_FAILED.getValue()) this.errorIsAscii = true; } } diff --git a/src/main/java/org/openflow/protocol/OFVendor.java b/src/main/java/org/openflow/protocol/OFVendor.java index 49fa4f1f3..8ecb862be 100644 --- a/src/main/java/org/openflow/protocol/OFVendor.java +++ b/src/main/java/org/openflow/protocol/OFVendor.java @@ -17,20 +17,22 @@ package org.openflow.protocol; -import java.util.Arrays; - import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; +import org.openflow.protocol.factory.OFVendorDataFactory; +import org.openflow.protocol.factory.OFVendorDataFactoryAware; +import org.openflow.protocol.vendor.OFVendorData; /** * Represents ofp_vendor_header * @author David Erickson (daviderickson@cs.stanford.edu) */ -public class OFVendor extends OFMessage { +public class OFVendor extends OFMessage implements OFVendorDataFactoryAware { public static int MINIMUM_LENGTH = 12; protected int vendor; - protected byte[] data; + protected OFVendorData vendorData; + protected OFVendorDataFactory vendorDataFactory; public OFVendor() { super(); @@ -52,36 +54,42 @@ public class OFVendor extends OFMessage { this.vendor = vendor; } + /** + * @return the data + */ + public OFVendorData getVendorData() { + return vendorData; + } + + /** + * @param data the data to set + */ + public void setVendorData(OFVendorData vendorData) { + this.vendorData = vendorData; + } + + @Override + public void setVendorDataFactory(OFVendorDataFactory vendorDataFactory) { + this.vendorDataFactory = vendorDataFactory; + } + @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.vendor = data.readInt(); - if (this.length > MINIMUM_LENGTH) { - this.data = new byte[this.length - MINIMUM_LENGTH]; - data.readBytes(this.data); - } + if (vendorDataFactory == null) + throw new RuntimeException("OFVendorDataFactory not set"); + + this.vendorData = vendorDataFactory.parseVendorData(vendor, + data, super.getLengthU() - MINIMUM_LENGTH); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeInt(this.vendor); - if (this.data != null) - data.writeBytes(this.data); - } - - /** - * @return the data - */ - public byte[] getData() { - return data; - } - - /** - * @param data the data to set - */ - public void setData(byte[] data) { - this.data = data; + if (vendorData != null) + vendorData.writeTo(data); } /* (non-Javadoc) @@ -91,8 +99,9 @@ public class OFVendor extends OFMessage { public int hashCode() { final int prime = 337; int result = super.hashCode(); - result = prime * result + Arrays.hashCode(data); result = prime * result + vendor; + if (vendorData != null) + result = prime * result + vendorData.hashCode(); return result; } @@ -108,10 +117,15 @@ public class OFVendor extends OFMessage { if (getClass() != obj.getClass()) return false; OFVendor other = (OFVendor) obj; - if (!Arrays.equals(data, other.data)) - return false; if (vendor != other.vendor) return false; + if (vendorData == null) { + if (other.vendorData != null) { + return false; + } + } else if (!vendorData.equals(other.vendorData)) { + return false; + } return true; } } diff --git a/src/main/java/org/openflow/protocol/factory/BasicFactory.java b/src/main/java/org/openflow/protocol/factory/BasicFactory.java index ac4c43275..e39732ade 100644 --- a/src/main/java/org/openflow/protocol/factory/BasicFactory.java +++ b/src/main/java/org/openflow/protocol/factory/BasicFactory.java @@ -28,6 +28,10 @@ import org.openflow.protocol.action.OFActionType; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; import org.openflow.protocol.statistics.OFVendorStatistics; +import org.openflow.protocol.vendor.OFByteArrayVendorData; +import org.openflow.protocol.vendor.OFVendorData; +import org.openflow.protocol.vendor.OFVendorDataType; +import org.openflow.protocol.vendor.OFVendorId; /** @@ -39,7 +43,7 @@ import org.openflow.protocol.statistics.OFVendorStatistics; * */ public class BasicFactory implements OFMessageFactory, OFActionFactory, - OFStatisticsFactory { + OFStatisticsFactory, OFVendorDataFactory { @Override public OFMessage getMessage(OFType t) { return t.newInstance(); @@ -74,6 +78,9 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory, if (ofm instanceof OFStatisticsFactoryAware) { ((OFStatisticsFactoryAware)ofm).setStatisticsFactory(this); } + if (ofm instanceof OFVendorDataFactoryAware) { + ((OFVendorDataFactoryAware)ofm).setVendorDataFactory(this); + } ofm.readFrom(data); if (OFMessage.class.equals(ofm.getClass())) { // advance the position for un-implemented messages @@ -203,4 +210,42 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory, } return results; // empty; no statistics at all } + + + @Override + public OFVendorData getVendorData(OFVendorId vendorId, + OFVendorDataType vendorDataType) { + if (vendorDataType == null) + return null; + + return vendorDataType.newInstance(); + } + + /** + * Attempts to parse and return the OFVendorData contained in the given + * ChannelBuffer, beginning right after the vendor id. + * @param vendor the vendor id that was parsed from the OFVendor message. + * @param data the ChannelBuffer from which to parse the vendor data + * @param length the length to the end of the enclosing message. + * @return an OFVendorData instance + */ + public OFVendorData parseVendorData(int vendor, ChannelBuffer data, + int length) { + OFVendorDataType vendorDataType = null; + OFVendorId vendorId = OFVendorId.lookupVendorId(vendor); + if (vendorId != null) { + data.markReaderIndex(); + vendorDataType = vendorId.parseVendorDataType(data, length); + data.resetReaderIndex(); + } + + OFVendorData vendorData = getVendorData(vendorId, vendorDataType); + if (vendorData == null) + vendorData = new OFByteArrayVendorData(); + + vendorData.readFrom(data, length); + + return vendorData; + } + } diff --git a/src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java b/src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java new file mode 100644 index 000000000..d754a4a31 --- /dev/null +++ b/src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java @@ -0,0 +1,69 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.protocol.factory; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.openflow.protocol.vendor.OFVendorData; +import org.openflow.protocol.vendor.OFVendorDataType; +import org.openflow.protocol.vendor.OFVendorId; + +/** + * The interface to factories used for parsing/creating OFVendorData instances. + * All methods are expected to be thread-safe. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public interface OFVendorDataFactory { + /** + * Retrieves an OFVendorData instance corresponding to the specified + * OFVendorId and OFVendorDataType. There are 3 possible cases for + * how this will be called: + * + * 1) If the vendor id in the OFVendor message is an unknown value, + * then this method is called with both vendorId and vendorDataType + * set to null. In this case typically the factory method should + * return an instance of OFGenericVendorData that just contains + * the raw byte array of the vendor data. + * + * 2) If the vendor id is known but no vendor data type has been + * registered for the data in the message, then vendorId is set to + * the appropriate OFVendorId instance and OFVendorDataType is set + * to null. This would typically be handled the same way as #1 + * + * 3) If both the vendor id and and vendor data type are known, then + * typically you'd just call the method in OFVendorDataType to + * instantiate the appropriate subclass of OFVendorData. + * + * @param vendorId the vendorId of the containing OFVendor message + * @param vendorDataType the type of the OFVendorData to be retrieved + * @return an OFVendorData instance + */ + public OFVendorData getVendorData(OFVendorId vendorId, + OFVendorDataType vendorDataType); + + /** + * Attempts to parse and return the OFVendorData contained in the given + * ChannelBuffer, beginning right after the vendor id. + * @param vendorId the vendor id that was parsed from the OFVendor message. + * @param data the ChannelBuffer from which to parse the vendor data + * @param length the length to the end of the enclosing message. + * @return an OFVendorData instance + */ + public OFVendorData parseVendorData(int vendorId, ChannelBuffer data, + int length); +} diff --git a/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java b/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java new file mode 100644 index 000000000..23614b0d0 --- /dev/null +++ b/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java @@ -0,0 +1,28 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.protocol.factory; + +/** + * Classes implementing this interface are expected to be instantiated with an + * instance of an OFVendorDataFactory + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public interface OFVendorDataFactoryAware { + public void setVendorDataFactory(OFVendorDataFactory vendorDataFactory); +} diff --git a/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java b/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java new file mode 100644 index 000000000..1f0e14b2d --- /dev/null +++ b/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java @@ -0,0 +1,71 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.protocol.vendor; + +import org.openflow.protocol.Instantiable; + +/** + * Subclass of OFVendorDataType that works with any vendor data format that + * begins with a integral value to indicate the format of the remaining data. + * It maps from the per-vendor-id integral data type code to the object + * used to instantiate the class associated with that vendor data type. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public class OFBasicVendorDataType extends OFVendorDataType { + + /** + * The data type value at the beginning of the vendor data. + */ + protected long type; + + /** + * Construct an empty (i.e. no specified data type value) vendor data type. + */ + public OFBasicVendorDataType() { + super(); + this.type = 0; + } + + /** + * Store some information about the vendor data type, including wire protocol + * type number, derived class and instantiator. + * + * @param type Wire protocol number associated with this vendor data type + * @param instantiator An Instantiator<OFVendorData> implementation that + * creates an instance of an appropriate subclass of OFVendorData. + */ + public OFBasicVendorDataType(long type, Instantiable<OFVendorData> instantiator) { + super(instantiator); + this.type = type; + } + + /** + * @return Returns the wire protocol value corresponding to this OFVendorDataType + */ + public long getTypeValue() { + return this.type; + } + + /** + * @param type the wire protocol value for this data type + */ + public void setTypeValue(long type) { + this.type = type; + } +} diff --git a/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java b/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java new file mode 100644 index 000000000..09365d7c5 --- /dev/null +++ b/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java @@ -0,0 +1,162 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.protocol.vendor; + +import java.util.HashMap; +import java.util.Map; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.openflow.protocol.Instantiable; + +/** + * Basic subclass of OFVendorId that works with any vendor data format where + * the data begins with an integral data type value. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public class OFBasicVendorId extends OFVendorId { + + /** + * The size of the data type value at the beginning of all vendor + * data associated with this vendor id. The data type size must be + * either 1, 2, 4 or 8. + */ + protected int dataTypeSize; + + /** + * Map of the vendor data types that have been registered for this + * vendor id. + */ + protected Map<Long, OFBasicVendorDataType> dataTypeMap = + new HashMap<Long, OFBasicVendorDataType>(); + + /** + * Construct an OFVendorId that where the vendor data begins + * with a data type value whose size is dataTypeSize. + * @param id the id of the vendor, typically the OUI of a vendor + * prefixed with 0. + * @param dataTypeSize the size of the integral data type value + * at the beginning of the vendor data. The value must be the + * size of an integeral data type (i.e. either 1,2,4 or 8). + */ + public OFBasicVendorId(int id, int dataTypeSize) { + super(id); + assert (dataTypeSize == 1) || (dataTypeSize == 2) || + (dataTypeSize == 4) || (dataTypeSize == 8); + this.dataTypeSize = dataTypeSize; + } + + /** + * Get the size of the data type value at the beginning of the vendor + * data. OFBasicVendorId assumes that this value is common across all of + * the vendor data formats associated with a given vendor id. + * @return + */ + public int getDataTypeSize() { + return dataTypeSize; + } + + /** + * Register a vendor data type with this vendor id. + * @param vendorDataType + */ + public void registerVendorDataType(OFBasicVendorDataType vendorDataType) { + dataTypeMap.put(vendorDataType.getTypeValue(), vendorDataType); + } + + /** + * Lookup the OFVendorDataType instance that has been registered with + * this vendor id. + * + * @param vendorDataType the integer code that was parsed from the + * @return + */ + public OFVendorDataType lookupVendorDataType(int vendorDataType) { + return dataTypeMap.get(vendorDataType); + } + + /** + * This function parses enough of the data from the buffer to be able + * to determine the appropriate OFVendorDataType for the data. It is meant + * to be a reasonably generic implementation that will work for most + * formats of vendor extensions. If the vendor data doesn't fit the + * assumptions listed below, then this method will need to be overridden + * to implement custom parsing. + * + * This implementation assumes that the vendor data begins with a data + * type code that is used to distinguish different formats of vendor + * data associated with a particular vendor ID. + * The exact format of the data is vendor-defined, so we don't know how + * how big the code is (or really even if there is a code). This code + * assumes that the common case will be that the data does include + * an initial type code (i.e. so that the vendor can have multiple + * message/data types) and that the size is either 1, 2 or 4 bytes. + * The size of the initial type code is configured by the subclass of + * OFVendorId. + * + * @param data the channel buffer containing the vendor data. + * @param length the length to the end of the enclosing message + * @return the OFVendorDataType that can be used to instantiate the + * appropriate subclass of OFVendorData. + */ + public OFVendorDataType parseVendorDataType(ChannelBuffer data, int length) { + OFVendorDataType vendorDataType = null; + + // Parse out the type code from the vendor data. + long dataTypeValue = 0; + if ((length == 0) || (length >= dataTypeSize)) { + switch (dataTypeSize) { + case 1: + dataTypeValue = data.readByte(); + break; + case 2: + dataTypeValue = data.readShort(); + break; + case 4: + dataTypeValue = data.readInt(); + break; + case 8: + dataTypeValue = data.readLong(); + break; + default: + // This would be indicative of a coding error where the + // dataTypeSize was specified incorrectly. This should have been + // caught in the constructor for OFVendorId. + assert false; + } + + vendorDataType = dataTypeMap.get(dataTypeValue); + } + + // If we weren't able to parse/map the data to a known OFVendorDataType, + // then map it to a generic vendor data type. + if (vendorDataType == null) { + vendorDataType = new OFBasicVendorDataType(dataTypeValue, + new Instantiable<OFVendorData>() { + @Override + public OFVendorData instantiate() { + return new OFByteArrayVendorData(); + } + } + ); + } + + return vendorDataType; + } + +} diff --git a/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java b/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java new file mode 100644 index 000000000..08fa00317 --- /dev/null +++ b/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java @@ -0,0 +1,94 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.protocol.vendor; + +import org.jboss.netty.buffer.ChannelBuffer; + +/** + * Basic implementation of OFVendorData that just treats the data as a + * byte array. This is used if there's an OFVendor message where there's + * no registered OFVendorId or no specific OFVendorDataType that can be + * determined from the data. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public class OFByteArrayVendorData implements OFVendorData { + + protected byte[] bytes; + + /** + * Construct vendor data with an empty byte array. + */ + public OFByteArrayVendorData() { + } + + /** + * Construct vendor data with the specified byte array. + * @param bytes + */ + public OFByteArrayVendorData(byte[] bytes) { + this.bytes = bytes; + } + + /** + * Get the associated byte array for this vendor data. + * @return the byte array containing the raw vendor data. + */ + public byte[] getBytes() { + return bytes; + } + + /** + * Set the byte array for the vendor data. + * @param bytes the raw byte array containing the vendor data. + */ + public void setBytes(byte[] bytes) { + this.bytes = bytes; + } + + /** + * Get the length of the vendor data. In this case it's just then length + * of the underlying byte array. + * @return the length of the vendor data + */ + @Override + public int getLength() { + return (bytes != null) ? bytes.length : 0; + } + + /** + * Read the vendor data from the ChannelBuffer into the byte array. + * @param data the channel buffer from which we're deserializing + * @param length the length to the end of the enclosing message + */ + @Override + public void readFrom(ChannelBuffer data, int length) { + bytes = new byte[length]; + data.readBytes(bytes); + } + + /** + * Write the vendor data bytes to the ChannelBuffer + * @param data the channel buffer to which we're serializing + */ + @Override + public void writeTo(ChannelBuffer data) { + if (bytes != null) + data.writeBytes(bytes); + } +} diff --git a/src/main/java/org/openflow/protocol/vendor/OFVendorData.java b/src/main/java/org/openflow/protocol/vendor/OFVendorData.java new file mode 100644 index 000000000..6dfb4e6cb --- /dev/null +++ b/src/main/java/org/openflow/protocol/vendor/OFVendorData.java @@ -0,0 +1,44 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.protocol.vendor; + +import org.jboss.netty.buffer.ChannelBuffer; + +/** + * The base class for all vendor data. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public interface OFVendorData { + /** + * @return length of the data + */ + public int getLength(); + + /** + * Read the vendor data from the specified ChannelBuffer + * @param data + */ + public void readFrom(ChannelBuffer data, int length); + + /** + * Write the vendor data to the specified ChannelBuffer + * @param data + */ + public void writeTo(ChannelBuffer data); +} diff --git a/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java b/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java new file mode 100644 index 000000000..ecae48239 --- /dev/null +++ b/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java @@ -0,0 +1,79 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.protocol.vendor; + +import org.openflow.protocol.Instantiable; + +/** + * Class that represents a specific vendor data type format in an + * OFVendor message. Typically the vendor data will begin with an integer + * code that determines the format of the rest of the data, but this + * class does not assume that. It's basically just a holder for an + * instantiator of the appropriate subclass of OFVendorData. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public class OFVendorDataType { + + /** + * Object that instantiates the subclass of OFVendorData + * associated with this data type. + */ + protected Instantiable<OFVendorData> instantiable; + + /** + * Construct an empty vendor data type. + */ + public OFVendorDataType() { + super(); + } + + /** + * Construct a vendor data type with the specified instantiable. + * @param instantiable object that creates the subclass of OFVendorData + * associated with this data type. + */ + public OFVendorDataType(Instantiable<OFVendorData> instantiable) { + this.instantiable = instantiable; + } + + /** + * Returns a new instance of a subclass of OFVendorData associated with + * this OFVendorDataType. + * + * @return the new object + */ + public OFVendorData newInstance() { + return instantiable.instantiate(); + } + + /** + * @return the instantiable + */ + public Instantiable<OFVendorData> getInstantiable() { + return instantiable; + } + + /** + * @param instantiable the instantiable to set + */ + public void setInstantiable(Instantiable<OFVendorData> instantiable) { + this.instantiable = instantiable; + } + +} diff --git a/src/main/java/org/openflow/protocol/vendor/OFVendorId.java b/src/main/java/org/openflow/protocol/vendor/OFVendorId.java new file mode 100644 index 000000000..f0af8a763 --- /dev/null +++ b/src/main/java/org/openflow/protocol/vendor/OFVendorId.java @@ -0,0 +1,85 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.protocol.vendor; + +import java.util.HashMap; +import java.util.Map; + +import org.jboss.netty.buffer.ChannelBuffer; + +/** + * Base class for the vendor ID corresponding to vendor extensions from a + * given vendor. It is responsible for knowing how to parse out some sort of + * data type value from the vendor data in an OFVendor message so that we can + * dispatch to the different subclasses of OFVendorData corresponding to the + * different formats of data for the vendor extensions. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public abstract class OFVendorId { + static Map<Integer, OFVendorId> mapping = new HashMap<Integer, OFVendorId>(); + + /** + * The vendor id value, typically the OUI of the vendor prefixed with 0. + */ + protected int id; + + /** + * Register a new vendor id. + * @param vendorId the vendor id to register + */ + public static void registerVendorId(OFVendorId vendorId) { + mapping.put(vendorId.getId(), vendorId); + } + + /** + * Lookup the OFVendorId instance corresponding to the given id value. + * @param id the integer vendor id value + * @return the corresponding OFVendorId that's been registered for the + * given value, or null if there id has not been registered. + */ + public static OFVendorId lookupVendorId(int id) { + return mapping.get(id); + } + + /** + * Create an OFVendorId with the give vendor id value + * @param id + */ + public OFVendorId(int id) { + this.id = id; + } + + /** + * @return the vendor id value + */ + public int getId() { + return id; + } + + /** + * This function parses enough of the data from the channel buffer to be + * able to determine the appropriate OFVendorDataType for the data. + * + * @param data the channel buffer containing the vendor data. + * @param length the length to the end of the enclosing message + * @return the OFVendorDataType that can be used to instantiate the + * appropriate subclass of OFVendorData. + */ + public abstract OFVendorDataType parseVendorDataType(ChannelBuffer data, int length); +} diff --git a/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java b/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java new file mode 100644 index 000000000..d6946a7b9 --- /dev/null +++ b/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java @@ -0,0 +1,97 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.vendor.nicira; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.openflow.protocol.vendor.OFVendorData; + +/** + * Base class for vendor data corresponding to a Nicira vendor extension. + * Nicira vendor data always starts with a 4-byte integer data type value. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public class OFNiciraVendorData implements OFVendorData { + + /** + * The value of the integer data type at the beginning of the vendor data + */ + protected int dataType; + + /** + * Construct empty (i.e. unspecified data type) Nicira vendor data. + */ + public OFNiciraVendorData() { + } + + /** + * Contruct Nicira vendor data with the specified data type + * @param dataType the data type value at the beginning of the vendor data. + */ + public OFNiciraVendorData(int dataType) { + this.dataType = dataType; + } + + /** + * Get the data type value at the beginning of the vendor data + * @return the integer data type value + */ + public int getDataType() { + return dataType; + } + + /** + * Set the data type value + * @param dataType the integer data type value at the beginning of the + * vendor data. + */ + public void setDataType(int dataType) { + this.dataType = dataType; + } + + /** + * Get the length of the vendor data. This implementation will normally + * be the superclass for another class that will override this to return + * the overall vendor data length. This implementation just returns the + * length of the part that includes the 4-byte integer data type value + * at the beginning of the vendor data. + */ + @Override + public int getLength() { + return 4; + } + + /** + * Read the vendor data from the ChannelBuffer + * @param data the channel buffer from which we're deserializing + * @param length the length to the end of the enclosing message + */ + @Override + public void readFrom(ChannelBuffer data, int length) { + dataType = data.readInt(); + } + + /** + * Write the vendor data to the ChannelBuffer + * @param data the channel buffer to which we're serializing + */ + @Override + public void writeTo(ChannelBuffer data) { + data.writeInt(dataType); + } +} diff --git a/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java b/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java new file mode 100644 index 000000000..302c911e4 --- /dev/null +++ b/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java @@ -0,0 +1,66 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.vendor.nicira; + +import org.openflow.protocol.Instantiable; +import org.openflow.protocol.vendor.OFVendorData; + +/** + * Subclass of OFVendorData representing the vendor data associated with + * a role reply vendor extension. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public class OFRoleReplyVendorData extends OFRoleVendorData { + + protected static Instantiable<OFVendorData> instantiable = + new Instantiable<OFVendorData>() { + public OFVendorData instantiate() { + return new OFRoleReplyVendorData(); + } + }; + + /** + * @return a subclass of Instantiable<OFVendorData> that instantiates + * an instance of OFRoleReplyVendorData. + */ + public static Instantiable<OFVendorData> getInstantiable() { + return instantiable; + } + + /** + * The data type value for a role reply + */ + public static final int NXT_ROLE_REPLY = 10; + + /** + * Construct a role reply vendor data with an unspecified role value. + */ + public OFRoleReplyVendorData() { + super(NXT_ROLE_REPLY); + } + + /** + * Construct a role reply vendor data with the specified role value. + * @param role the role value for the role reply. Should be one of + * NX_ROLE_OTHER, NX_ROLE_MASTER or NX_ROLE_SLAVE. + */ + public OFRoleReplyVendorData(int role) { + super(NXT_ROLE_REPLY, role); + } +} diff --git a/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java b/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java new file mode 100644 index 000000000..88eb58124 --- /dev/null +++ b/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java @@ -0,0 +1,66 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.vendor.nicira; + +import org.openflow.protocol.Instantiable; +import org.openflow.protocol.vendor.OFVendorData; + +/** + * Subclass of OFVendorData representing the vendor data associated with + * a role request vendor extension. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public class OFRoleRequestVendorData extends OFRoleVendorData { + + protected static Instantiable<OFVendorData> instantiable = + new Instantiable<OFVendorData>() { + public OFVendorData instantiate() { + return new OFRoleRequestVendorData(); + } + }; + + /** + * @return a subclass of Instantiable<OFVendorData> that instantiates + * an instance of OFRoleRequestVendorData. + */ + public static Instantiable<OFVendorData> getInstantiable() { + return instantiable; + } + + /** + * The data type value for a role request + */ + public static final int NXT_ROLE_REQUEST = 9; + + /** + * Construct a role request vendor data with an unspecified role value. + */ + public OFRoleRequestVendorData() { + super(NXT_ROLE_REQUEST); + } + + /** + * Construct a role request vendor data with the specified role value. + * @param role the role value for the role request. Should be one of + * NX_ROLE_OTHER, NX_ROLE_MASTER or NX_ROLE_SLAVE. + */ + public OFRoleRequestVendorData(int role) { + super(NXT_ROLE_REQUEST, role); + } +} diff --git a/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java b/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java new file mode 100644 index 000000000..e7c8bf213 --- /dev/null +++ b/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java @@ -0,0 +1,113 @@ +/** +* Copyright 2011, Big Switch Networks, Inc. +* Originally created by David Erickson & Rob Sherwood, Stanford University +* +* 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 org.openflow.vendor.nicira; + +import org.jboss.netty.buffer.ChannelBuffer; + +/** + * Class that represents the vendor data in the role request + * extension implemented by Open vSwitch to support high availability. + * + * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) + */ +public class OFRoleVendorData extends OFNiciraVendorData { + + /** + * Role value indicating that the controller is in the OTHER role. + */ + public static final int NX_ROLE_OTHER = 0; + + /** + * Role value indicating that the controller is in the MASTER role. + */ + public static final int NX_ROLE_MASTER = 1; + + /** + * Role value indicating that the controller is in the SLAVE role. + */ + public static final int NX_ROLE_SLAVE = 2; + + protected int role; + + /** + * Construct an uninitialized OFRoleVendorData + */ + public OFRoleVendorData() { + super(); + } + + /** + * Construct an OFRoleVendorData with the specified data type + * (i.e. either request or reply) and an unspecified role. + * @param dataType + */ + public OFRoleVendorData(int dataType) { + super(dataType); + } + + /** + * Construct an OFRoleVendorData with the specified data type + * (i.e. either request or reply) and role (i.e. one of of + * master, slave, or other). + * @param dataType either role request or role reply data type + */ + public OFRoleVendorData(int dataType, int role) { + super(dataType); + this.role = role; + } + /** + * @return the role value of the role vendor data + */ + public int getRole() { + return role; + } + + /** + * @param role the role value of the role vendor data + */ + public void setRole(int role) { + this.role = role; + } + + /** + * @return the total length of the role vendor data + */ + @Override + public int getLength() { + return super.getLength() + 4; + } + + /** + * Read the role vendor data from the ChannelBuffer + * @param data the channel buffer from which we're deserializing + * @param length the length to the end of the enclosing message + */ + public void readFrom(ChannelBuffer data, int length) { + super.readFrom(data, length); + role = data.readInt(); + } + + /** + * Write the role vendor data to the ChannelBuffer + * @param data the channel buffer to which we're serializing + */ + public void writeTo(ChannelBuffer data) { + super.writeTo(data); + data.writeInt(role); + } +} diff --git a/src/test/java/org/openflow/protocol/OFErrorTest.java b/src/test/java/org/openflow/protocol/OFErrorTest.java index c05f583b7..85c544d98 100644 --- a/src/test/java/org/openflow/protocol/OFErrorTest.java +++ b/src/test/java/org/openflow/protocol/OFErrorTest.java @@ -32,14 +32,14 @@ public class OFErrorTest extends OFTestCase { public void testWriteRead() throws Exception { OFError msg = (OFError) messageFactory.getMessage(OFType.ERROR); msg.setMessageFactory(messageFactory); - msg.setErrorType((short) OFErrorType.OFPET_HELLO_FAILED.ordinal()); + msg.setErrorType((short) OFErrorType.OFPET_HELLO_FAILED.getValue()); msg.setErrorCode((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE .ordinal()); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); - TestCase.assertEquals((short) OFErrorType.OFPET_HELLO_FAILED.ordinal(), + TestCase.assertEquals((short) OFErrorType.OFPET_HELLO_FAILED.getValue(), msg.getErrorType()); TestCase.assertEquals((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE .ordinal(), msg.getErrorType()); @@ -49,7 +49,7 @@ public class OFErrorTest extends OFTestCase { bb.clear(); msg.writeTo(bb); msg.readFrom(bb); - TestCase.assertEquals((short) OFErrorType.OFPET_HELLO_FAILED.ordinal(), + TestCase.assertEquals((short) OFErrorType.OFPET_HELLO_FAILED.getValue(), msg.getErrorType()); TestCase.assertEquals((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE .ordinal(), msg.getErrorType()); diff --git a/src/test/java/org/openflow/protocol/OFVendorTest.java b/src/test/java/org/openflow/protocol/OFVendorTest.java index 50b641b5c..b85a915a9 100644 --- a/src/test/java/org/openflow/protocol/OFVendorTest.java +++ b/src/test/java/org/openflow/protocol/OFVendorTest.java @@ -17,20 +17,199 @@ package org.openflow.protocol; +import java.util.Arrays; + import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; +import org.openflow.protocol.factory.BasicFactory; +import org.openflow.protocol.vendor.OFByteArrayVendorData; +import org.openflow.protocol.vendor.OFBasicVendorDataType; +import org.openflow.protocol.vendor.OFBasicVendorId; +import org.openflow.protocol.vendor.OFVendorData; +import org.openflow.protocol.vendor.OFVendorId; import org.openflow.util.OFTestCase; public class OFVendorTest extends OFTestCase { - public void testWriteRead() throws Exception { + + public static int ACME_VENDOR_ID = 0x00112233; + + static class AcmeVendorData implements OFVendorData { + protected int dataType; + + public int getLength() { + return 4; + } + + public void readFrom(ChannelBuffer data, int length) { + dataType = data.readInt(); + } + + public void writeTo(ChannelBuffer data) { + data.writeInt(dataType); + } + } + + static class AcmeVendorData1 extends AcmeVendorData { + public short flags; + public short value; + + public static int DATA_TYPE = 1; + + public AcmeVendorData1() { + } + + public AcmeVendorData1(short flags, short value) { + this.dataType = DATA_TYPE; + this.flags = flags; + this.value = value; + } + + public short getFlags() { + return flags; + } + + public short getValue() { + return value; + } + + public int getLength() { + return 8; + } + + public void readFrom(ChannelBuffer data, int length) { + super.readFrom(data, length); + flags = data.readShort(); + value = data.readShort(); + + } + public void writeTo(ChannelBuffer data) { + super.writeTo(data); + data.writeShort(flags); + data.writeShort(value); + } + + public static Instantiable<OFVendorData> getInstantiable() { + return new Instantiable<OFVendorData>() { + public OFVendorData instantiate() { + return new AcmeVendorData1(); + } + }; + } + } + + static class AcmeVendorData2 extends AcmeVendorData { + public int type; + public int subtype; + + public static int DATA_TYPE = 2; + + public AcmeVendorData2() { + } + + public AcmeVendorData2(int type, int subtype) { + this.dataType = DATA_TYPE; + this.type = type; + this.subtype = subtype; + } + + public int getType() { + return type; + } + + public int getSubtype() { + return subtype; + } + + public int getLength() { + return 12; + } + + public void readFrom(ChannelBuffer data, int length) { + super.readFrom(data, length); + type = data.readShort(); + subtype = data.readShort(); + + } + public void writeTo(ChannelBuffer data) { + super.writeTo(data); + data.writeShort(type); + data.writeShort(subtype); + } + + public static Instantiable<OFVendorData> getInstantiable() { + return new Instantiable<OFVendorData>() { + public OFVendorData instantiate() { + return new AcmeVendorData2(); + } + }; + } + } + + { + OFBasicVendorId acmeVendorId = new OFBasicVendorId(ACME_VENDOR_ID, 4); + OFVendorId.registerVendorId(acmeVendorId); + OFBasicVendorDataType acmeVendorData1 = new OFBasicVendorDataType( + AcmeVendorData1.DATA_TYPE, AcmeVendorData1.getInstantiable()); + acmeVendorId.registerVendorDataType(acmeVendorData1); + OFBasicVendorDataType acmeVendorData2 = new OFBasicVendorDataType( + AcmeVendorData2.DATA_TYPE, AcmeVendorData2.getInstantiable()); + acmeVendorId.registerVendorDataType(acmeVendorData2); + } + + private OFVendor makeVendorMessage(int vendor) { OFVendor msg = (OFVendor) messageFactory.getMessage(OFType.VENDOR); - msg.setVendor(1); + msg.setVendorDataFactory(new BasicFactory()); + msg.setVendor(vendor); + return msg; + } + + public void testWriteRead() throws Exception { + OFVendor msg = makeVendorMessage(1); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(1, msg.getVendor()); } + + public void testVendorData() throws Exception { + OFVendor msg = makeVendorMessage(ACME_VENDOR_ID); + OFVendorData vendorData = new AcmeVendorData1((short)11, (short)22); + msg.setVendorData(vendorData); + msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength()); + ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); + bb.clear(); + msg.writeTo(bb); + msg.readFrom(bb); + assertEquals(ACME_VENDOR_ID, msg.getVendor()); + AcmeVendorData1 vendorData1 = (AcmeVendorData1) msg.getVendorData(); + assertEquals(11, vendorData1.getFlags()); + assertEquals(22, vendorData1.getValue()); + + vendorData = new AcmeVendorData2(33, 44); + msg.setVendorData(vendorData); + msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength()); + bb.clear(); + msg.writeTo(bb); + msg.readFrom(bb); + assertEquals(ACME_VENDOR_ID, msg.getVendor()); + AcmeVendorData2 vendorData2 = (AcmeVendorData2) msg.getVendorData(); + assertEquals(33, vendorData2.getType()); + assertEquals(44, vendorData2.getSubtype()); + + final int DUMMY_VENDOR_ID = 55; + msg.setVendor(DUMMY_VENDOR_ID); + byte[] genericVendorDataBytes = new byte[] {0x55, 0x66}; + vendorData = new OFByteArrayVendorData(genericVendorDataBytes); + msg.setVendorData(vendorData); + msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength()); + bb.clear(); + msg.writeTo(bb); + msg.readFrom(bb); + assertEquals(DUMMY_VENDOR_ID, msg.getVendor()); + OFByteArrayVendorData genericVendorData = (OFByteArrayVendorData) msg.getVendorData(); + assertTrue(Arrays.equals(genericVendorDataBytes, genericVendorData.getBytes())); + } } -- GitLab