--- /dev/null
+/*
+ * Copyright (c) 2015 Pantheon Technologies s.r.o. 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.openflowjava.protocol.api.connection;
+
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.Error;
+
+/**
+ * Exception which is used to report that a particular request failed on the
+ * remote device (switch).
+ */
+public class DeviceRequestFailedException extends Exception {
+ private static final long serialVersionUID = 1L;
+ private final Error error;
+
+ public DeviceRequestFailedException(final String message, @Nonnull final Error error) {
+ super(message);
+ this.error = Preconditions.checkNotNull(error);
+ }
+
+ public DeviceRequestFailedException(final String message, @Nonnull final Error error, final Throwable cause) {
+ super(message, cause);
+ this.error = Preconditions.checkNotNull(error);
+ }
+
+ @Nonnull public Error getError() {
+ return error;
+ }
+}
messageListener.onEchoRequestMessage((EchoRequestMessage) message);
statisticsCounters.incrementCounter(CounterEventTypes.US_MESSAGE_PASS);
} else if (message instanceof ErrorMessage) {
- messageListener.onErrorMessage((ErrorMessage) message);
- if (outputManager != null) {
- outputManager.onMessage((OfHeader) message);
+ // Send only unmatched errors
+ if (outputManager == null || !outputManager.onMessage((OfHeader) message)) {
+ messageListener.onErrorMessage((ErrorMessage) message);
}
statisticsCounters.incrementCounter(CounterEventTypes.US_MESSAGE_PASS);
} else if (message instanceof ExperimenterMessage) {
- messageListener.onExperimenterMessage((ExperimenterMessage) message);
if (outputManager != null) {
outputManager.onMessage((OfHeader) message);
}
+ messageListener.onExperimenterMessage((ExperimenterMessage) message);
statisticsCounters.incrementCounter(CounterEventTypes.US_MESSAGE_PASS);
} else if (message instanceof FlowRemovedMessage) {
messageListener.onFlowRemovedMessage((FlowRemovedMessage) message);
messageListener.onHelloMessage((HelloMessage) message);
statisticsCounters.incrementCounter(CounterEventTypes.US_MESSAGE_PASS);
} else if (message instanceof MultipartReplyMessage) {
- messageListener.onMultipartReplyMessage((MultipartReplyMessage) message);
if (outputManager != null) {
outputManager.onMessage((OfHeader) message);
}
+ messageListener.onMultipartReplyMessage((MultipartReplyMessage) message);
statisticsCounters.incrementCounter(CounterEventTypes.US_MESSAGE_PASS);
} else if (message instanceof PacketInMessage) {
messageListener.onPacketInMessage((PacketInMessage) message);
package org.opendaylight.openflowjava.protocol.impl.core.connection;
import com.google.common.base.Preconditions;
+import com.google.common.base.Verify;
import com.google.common.util.concurrent.FutureCallback;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import javax.annotation.Nonnull;
import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
+import org.opendaylight.openflowjava.protocol.api.connection.DeviceRequestFailedException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.Error;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
}
}
- private boolean xidInRance(final long xid) {
+ // Argument is 'long' to explicitly convert before performing operations
+ private boolean xidInRange(final long xid) {
return xid < endXid && (xid >= baseXid || baseXid > endXid);
}
+ private static boolean completeEntry(final OutboundQueueEntry entry, final OfHeader response) {
+ if (response instanceof Error) {
+ final Error err = (Error)response;
+ LOG.debug("Device-reported request XID {} failed {}:{}", response.getXid(), err.getTypeString(), err.getCodeString());
+ entry.fail(new DeviceRequestFailedException("Device-side failure", err));
+ return true;
+ } else {
+ return entry.complete(response);
+ }
+ }
+
/**
* Return the request entry corresponding to a response. Returns null
* if there is no request matching the response.
*/
OutboundQueueEntry pairRequest(@Nonnull final OfHeader response) {
final Long xid = response.getXid();
- if (!xidInRance(xid)) {
+ if (!xidInRange(xid)) {
LOG.debug("Queue {} {}/{} ignoring XID {}", this, baseXid, queue.length, xid);
return null;
}
return null;
}
- if (entry.complete(response)) {
+ if (entry.isBarrier()) {
+ // This has been a barrier -- make sure we complete all preceding requests.
+ // XXX: Barriers are expected to complete in one message.
+ // If this assumption is changed, this logic will need to be expanded
+ // to ensure that the requests implied by the barrier are reported as
+ // completed *after* the barrier.
+ LOG.trace("Barrier XID {} completed, cascading completion to XIDs {} to {}", xid, baseXid + lastBarrierOffset + 1, xid - 1);
+ completeRequests(offset);
+ lastBarrierOffset = offset;
+
+ final boolean success = completeEntry(entry, response);
+ Verify.verify(success, "Barrier request failed to complete");
+ completeCount++;
+ } else if (completeEntry(entry, response)) {
completeCount++;
-
- // This has been a barrier -- make sure we complete all preceding requests
- if (entry.isBarrier()) {
- LOG.debug("Barrier XID {} completed, cascading completion to XIDs {} to {}", xid, baseXid + lastBarrierOffset + 1, xid - 1);
- completeRequests(offset);
- lastBarrierOffset = offset;
- }
}
+
return entry;
}