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