--- /dev/null
+/**
+* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+* 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;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.factory.MessageParseException;
+import org.openflow.protocol.factory.OFMessageFactory;
+import org.openflow.protocol.factory.OFMessageFactoryAware;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_error_msg
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class OFError extends OFMessage implements OFMessageFactoryAware {
+ public static int MINIMUM_LENGTH = 12;
+
+ public enum OFErrorType {
+ // 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 is 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 {
+ OFPHFC_INCOMPATIBLE, OFPHFC_EPERM
+ }
+
+ public enum OFBadRequestCode {
+ OFPBRC_BAD_VERSION, OFPBRC_BAD_TYPE, OFPBRC_BAD_STAT, OFPBRC_BAD_VENDOR, OFPBRC_BAD_SUBTYPE, OFPBRC_EPERM, OFPBRC_BAD_LEN, OFPBRC_BUFFER_EMPTY, OFPBRC_BUFFER_UNKNOWN
+ }
+
+ public enum OFBadActionCode {
+ OFPBAC_BAD_TYPE, OFPBAC_BAD_LEN, OFPBAC_BAD_VENDOR, OFPBAC_BAD_VENDOR_TYPE, OFPBAC_BAD_OUT_PORT, OFPBAC_BAD_ARGUMENT, OFPBAC_EPERM, OFPBAC_TOO_MANY, OFPBAC_BAD_QUEUE
+ }
+
+ public enum OFFlowModFailedCode {
+ OFPFMFC_ALL_TABLES_FULL, OFPFMFC_OVERLAP, OFPFMFC_EPERM, OFPFMFC_BAD_EMERG_TIMEOUT, OFPFMFC_BAD_COMMAND, OFPFMFC_UNSUPPORTED
+ }
+
+ public enum OFPortModFailedCode {
+ OFPPMFC_BAD_PORT, OFPPMFC_BAD_HW_ADDR
+ }
+
+ public enum OFQueueOpFailedCode {
+ OFPQOFC_BAD_PORT, OFPQOFC_BAD_QUEUE, OFPQOFC_EPERM
+ }
+
+ protected short errorType;
+ protected short errorCode;
+ protected int vendor;
+ protected int vendorErrorType;
+ protected short vendorErrorCode;
+ protected OFMessageFactory factory;
+ protected byte[] error;
+ protected boolean errorIsAscii;
+
+ public OFError() {
+ super();
+ this.type = OFType.ERROR;
+ this.length = U16.t(MINIMUM_LENGTH);
+ }
+
+ /** convenience constructor */
+ public OFError(OFErrorType errorType) {
+ this();
+ setErrorType(errorType);
+ }
+
+ /**
+ * @return the errorType
+ */
+ public short getErrorType() {
+ return errorType;
+ }
+
+ /**
+ * @param errorType
+ * the errorType to set
+ */
+ public void setErrorType(short errorType) {
+ this.errorType = errorType;
+ }
+
+ public void setErrorType(OFErrorType type) {
+ 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
+ */
+ public short getErrorCode() {
+ return errorCode;
+ }
+
+ /**
+ * @param errorCode
+ * the errorCode to set
+ */
+ public void setErrorCode(OFHelloFailedCode code) {
+ this.errorCode = (short) code.ordinal();
+ }
+
+ public void setErrorCode(short errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ public void setErrorCode(OFBadRequestCode code) {
+ this.errorCode = (short) code.ordinal();
+ }
+
+ public void setErrorCode(OFBadActionCode code) {
+ this.errorCode = (short) code.ordinal();
+ }
+
+ public void setErrorCode(OFFlowModFailedCode code) {
+ this.errorCode = (short) code.ordinal();
+ }
+
+ public void setErrorCode(OFPortModFailedCode code) {
+ this.errorCode = (short) code.ordinal();
+ }
+
+ public void setErrorCode(OFQueueOpFailedCode code) {
+ this.errorCode = (short) code.ordinal();
+ }
+
+ public int getVendorErrorType() {
+ return vendorErrorType;
+ }
+
+ public void setVendorErrorType(int vendorErrorType) {
+ this.vendorErrorType = vendorErrorType;
+ }
+
+ public short getVendorErrorCode() {
+ return vendorErrorCode;
+ }
+
+ public void setVendorErrorCode(short vendorErrorCode) {
+ this.vendorErrorCode = vendorErrorCode;
+ }
+
+ public OFMessage getOffendingMsg() throws MessageParseException {
+ // should only have one message embedded; if more than one, just
+ // grab first
+ if (this.error == null)
+ return null;
+ ChannelBuffer errorMsg = ChannelBuffers.wrappedBuffer(this.error);
+ if (factory == null)
+ throw new RuntimeException("MessageFactory not set");
+
+ List<OFMessage> msglist = this.factory.parseMessage(errorMsg);
+ if (msglist == null)
+ return null;
+ return msglist.get(0);
+ }
+
+ /**
+ * Write this offending message into the payload of the Error message
+ *
+ * @param offendingMsg
+ */
+
+ public void setOffendingMsg(OFMessage offendingMsg) {
+ if (offendingMsg == null) {
+ super.setLengthU(MINIMUM_LENGTH);
+ } else {
+ this.error = new byte[offendingMsg.getLengthU()];
+ ChannelBuffer data = ChannelBuffers.wrappedBuffer(this.error);
+ data.writerIndex(0);
+ offendingMsg.writeTo(data);
+ super.setLengthU(MINIMUM_LENGTH + offendingMsg.getLengthU());
+ }
+ }
+
+ public OFMessageFactory getFactory() {
+ return factory;
+ }
+
+ @Override
+ public void setMessageFactory(OFMessageFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
+ * @return the error
+ */
+ public byte[] getError() {
+ return error;
+ }
+
+ /**
+ * @param error
+ * the error to set
+ */
+ public void setError(byte[] error) {
+ this.error = error;
+ }
+
+ /**
+ * @return the errorIsAscii
+ */
+ public boolean isErrorIsAscii() {
+ return errorIsAscii;
+ }
+
+ /**
+ * @param errorIsAscii
+ * the errorIsAscii to set
+ */
+ public void setErrorIsAscii(boolean errorIsAscii) {
+ this.errorIsAscii = errorIsAscii;
+ }
+
+ @Override
+ public void readFrom(ChannelBuffer data) {
+ super.readFrom(data);
+ this.errorType = data.readShort();
+ this.errorCode = data.readShort();
+ int dataLength = this.getLengthU() - MINIMUM_LENGTH;
+ if (dataLength > 0) {
+ this.error = new byte[dataLength];
+ data.readBytes(this.error);
+ if (this.errorType == OFErrorType.OFPET_HELLO_FAILED.getValue())
+ this.errorIsAscii = true;
+ }
+ }
+
+ @Override
+ public void writeTo(ChannelBuffer data) {
+ super.writeTo(data);
+ data.writeShort(errorType);
+ data.writeShort(errorCode);
+ if (error != null)
+ data.writeBytes(error);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Arrays.hashCode(error);
+ result = prime * result + errorCode;
+ result = prime * result + (errorIsAscii ? 1231 : 1237);
+ result = prime * result + errorType;
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ OFError other = (OFError) obj;
+ if (!Arrays.equals(error, other.error))
+ return false;
+ if (errorCode != other.errorCode)
+ return false;
+ if (errorIsAscii != other.errorIsAscii)
+ return false;
+ if (errorType != other.errorType)
+ return false;
+ return true;
+ }
+
+}