/**
* 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);
}
/**
* @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;
}
}