import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.protocol.framework.AbstractSessionNegotiator;
-import org.opendaylight.protocol.pcep.PCEPErrors;
-import org.opendaylight.protocol.pcep.message.PCEPErrorMessage;
-import org.opendaylight.protocol.pcep.message.PCEPOpenMessage;
-import org.opendaylight.protocol.pcep.object.PCEPErrorObject;
-import org.opendaylight.protocol.pcep.object.PCEPOpenObject;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.KeepaliveMessage;
+import org.opendaylight.protocol.pcep.spi.PCEPErrors;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Keepalive;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.KeepaliveBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.OpenBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Pcerr;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.OpenMessage;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.keepalive.message.KeepaliveMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.message.OpenMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Open;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcerr.message.pcerr.message.error.type.SessionCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
/**
* Abstract PCEP session negotiator. Takes care of basic handshake without implementing a specific policy. Policies need
* action is to terminate negotiation. This timer is restarted between state transitions and runs in all states
* except Idle and Finished.
*/
- private enum State {
+ @VisibleForTesting
+ public enum State {
/**
* Negotiation has not begun. It will be activated once we are asked to provide our initial proposal, at which
* point we move into OpenWait state.
Finished,
}
- private static final Logger logger = LoggerFactory.getLogger(AbstractPCEPSessionNegotiator.class);
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractPCEPSessionNegotiator.class);
+
private final Timer timer;
@GuardedBy("this")
private Timeout failTimer;
@GuardedBy("this")
- private PCEPOpenObject localPrefs;
+ private Open localPrefs;
@GuardedBy("this")
- private PCEPOpenObject remotePrefs;
+ private Open remotePrefs;
private volatile boolean localOK, openRetry, remoteOK;
+ private final Keepalive keepalive = new KeepaliveBuilder().setKeepaliveMessage(new KeepaliveMessageBuilder().build()).build();
+
protected AbstractPCEPSessionNegotiator(final Timer timer, final Promise<PCEPSessionImpl> promise, final Channel channel) {
super(promise, channel);
this.timer = Preconditions.checkNotNull(timer);
*
* @return Session parameters proposal.
*/
- protected abstract PCEPOpenObject getInitialProposal();
+ protected abstract Open getInitialProposal();
/**
* Get the revised session parameters proposal based on the feedback the peer has provided to us.
*
* @param suggestion Peer-provided suggested session parameters
- * @return Session parameters proposal.
+ * @return Session parameters proposal, or null if peers session parameters preclude us from suggesting anything
*/
- protected abstract PCEPOpenObject getRevisedProposal(PCEPOpenObject suggestion);
+ protected abstract Open getRevisedProposal(Open suggestion);
/**
* Check whether a peer-provided session parameters proposal is acceptable.
* @param proposal peer-proposed session parameters
* @return true if the proposal is acceptable, false otherwise
*/
- protected abstract boolean isProposalAcceptable(PCEPOpenObject proposal);
+ protected abstract boolean isProposalAcceptable(Open proposal);
/**
* Given a peer-provided session parameters proposal which we found unacceptable, provide a counter-proposal. The
* @param proposal unacceptable peer proposal
* @return our counter-proposal, or null if there is no way to negotiate an acceptable proposal
*/
- protected abstract PCEPOpenObject getCounterProposal(PCEPOpenObject proposal);
+ protected abstract Open getCounterProposal(Open proposal);
/**
* Create the protocol session.
* @param remotePrefs Session preferences proposed by the peer and accepted by us.
* @return New protocol session.
*/
- protected abstract PCEPSessionImpl createSession(Timer timer, Channel channel, PCEPOpenObject localPrefs, PCEPOpenObject remotePrefs);
+ protected abstract PCEPSessionImpl createSession(Timer timer, Channel channel, Open localPrefs, Open remotePrefs);
/**
* Sends PCEP Error Message with one PCEPError.
* @param value
*/
private void sendErrorMessage(final PCEPErrors value) {
- this.channel.writeAndFlush(new PCEPErrorMessage(ImmutableList.of(new PCEPErrorObject(value))));
+
+ this.channel.writeAndFlush(Util.createErrorMessage(value, null));
}
private void scheduleFailTimer() {
this.failTimer = this.timer.newTimeout(new TimerTask() {
@Override
- public void run(final Timeout timeout) throws Exception {
+ public void run(final Timeout timeout) {
synchronized (lock) {
// This closes the race between timer expiring and new timer
// being armed while it waits for the lock.
}
@Override
- final synchronized protected void startNegotiation() {
+ protected final synchronized void startNegotiation() {
Preconditions.checkState(this.state == State.Idle);
this.localPrefs = getInitialProposal();
- this.channel.writeAndFlush(new PCEPOpenMessage(this.localPrefs));
+ final OpenMessage m = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.OpenBuilder().setOpenMessage(
+ new OpenMessageBuilder().setOpen(this.localPrefs).build()).build();
+ this.channel.writeAndFlush(m);
this.state = State.OpenWait;
scheduleFailTimer();
- logger.debug("Channel {} started sent proposal {}", this.channel, this.localPrefs);
+ LOG.debug("Channel {} started sent proposal {}", this.channel, this.localPrefs);
}
@Override
- final synchronized protected void handleMessage(final Message msg) throws Exception {
+ protected final synchronized void handleMessage(final Message msg) {
this.failTimer.cancel();
- logger.debug("Channel {} handling message in state {}", this.channel, this.state);
+ LOG.debug("Channel {} handling message in state {}", this.channel, this.state);
switch (this.state) {
case Finished:
case Idle:
throw new IllegalStateException("Unexpected handleMessage in state " + this.state);
case KeepWait:
- if (msg instanceof KeepaliveMessage) {
+ if (msg instanceof Keepalive) {
this.localOK = true;
if (this.remoteOK) {
negotiationSuccessful(createSession(this.timer, this.channel, this.localPrefs, this.remotePrefs));
} else {
scheduleFailTimer();
this.state = State.OpenWait;
- logger.debug("Channel {} moved to OpenWait state with localOK=1", this.channel);
+ LOG.debug("Channel {} moved to OpenWait state with localOK=1", this.channel);
}
return;
- } else if (msg instanceof PCEPErrorMessage) {
- final PCEPErrorMessage err = (PCEPErrorMessage) msg;
- this.localPrefs = getRevisedProposal(err.getOpenObject());
+ } else if (msg instanceof Pcerr) {
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcerr.message.PcerrMessage err = ((Pcerr) msg).getPcerrMessage();
+ this.localPrefs = getRevisedProposal(((SessionCase) err.getErrorType()).getSession().getOpen());
if (this.localPrefs == null) {
sendErrorMessage(PCEPErrors.PCERR_NON_ACC_SESSION_CHAR);
negotiationFailed(new RuntimeException("Peer suggested unacceptable retry proposal"));
this.state = State.Finished;
return;
}
-
+ this.channel.writeAndFlush(new OpenBuilder().setOpenMessage(new OpenMessageBuilder().setOpen(this.localPrefs).build()).build());
if (!this.remoteOK) {
this.state = State.OpenWait;
}
break;
case OpenWait:
- if (msg instanceof PCEPOpenMessage) {
- final PCEPOpenObject open = ((PCEPOpenMessage) msg).getOpenObject();
+ if (msg instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Open) {
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.message.OpenMessage o = ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Open) msg).getOpenMessage();
+ final Open open = o.getOpen();
if (isProposalAcceptable(open)) {
- this.channel.writeAndFlush(new KeepaliveMessageBuilder().build());
+ this.channel.writeAndFlush(this.keepalive);
this.remotePrefs = open;
this.remoteOK = true;
if (this.localOK) {
} else {
scheduleFailTimer();
this.state = State.KeepWait;
- logger.debug("Channel {} moved to KeepWait state with remoteOK=1", this.channel);
+ LOG.debug("Channel {} moved to KeepWait state with remoteOK=1", this.channel);
}
return;
}
return;
}
- final PCEPOpenObject newPrefs = getCounterProposal(open);
+ final Open newPrefs = getCounterProposal(open);
if (newPrefs == null) {
sendErrorMessage(PCEPErrors.NON_ACC_NON_NEG_SESSION_CHAR);
negotiationFailed(new RuntimeException("Peer sent unacceptable session parameters"));
return;
}
- this.channel.writeAndFlush(new PCEPErrorMessage(newPrefs, ImmutableList.of(new PCEPErrorObject(PCEPErrors.NON_ACC_NEG_SESSION_CHAR)), null));
+ this.channel.writeAndFlush(Util.createErrorMessage(PCEPErrors.NON_ACC_NEG_SESSION_CHAR, newPrefs));
this.openRetry = true;
this.state = this.localOK ? State.OpenWait : State.KeepWait;
break;
}
- logger.warn("Channel {} in state {} received unexpected message {}", this.channel, this.state, msg);
+ LOG.warn("Channel {} in state {} received unexpected message {}", this.channel, this.state, msg);
sendErrorMessage(PCEPErrors.NON_OR_INVALID_OPEN_MSG);
negotiationFailed(new Exception("Illegal message encountered"));
this.state = State.Finished;
}
+
+ public synchronized State getState() {
+ return this.state;
+ }
}