2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.bgp.rib.impl;
10 import io.netty.channel.Channel;
11 import io.netty.util.Timeout;
12 import io.netty.util.Timer;
13 import io.netty.util.TimerTask;
14 import io.netty.util.concurrent.Promise;
16 import java.util.concurrent.TimeUnit;
18 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
19 import org.opendaylight.protocol.bgp.parser.BGPError;
20 import org.opendaylight.protocol.bgp.parser.BGPMessage;
21 import org.opendaylight.protocol.bgp.parser.BGPSessionListener;
22 import org.opendaylight.protocol.bgp.parser.message.BGPKeepAliveMessage;
23 import org.opendaylight.protocol.bgp.parser.message.BGPNotificationMessage;
24 import org.opendaylight.protocol.bgp.parser.message.BGPOpenMessage;
25 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
26 import org.opendaylight.protocol.framework.AbstractSessionNegotiator;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
30 import com.google.common.base.Preconditions;
32 public final class BGPSessionNegotiator extends AbstractSessionNegotiator<BGPMessage, BGPSessionImpl> {
33 // 4 minutes recommended in http://tools.ietf.org/html/rfc4271#section-8.2.2
34 private static final int INITIAL_HOLDTIMER = 4;
38 * Negotiation has not started yet.
42 * We have sent our Open message, and are waiting for the peer's Open message.
46 * We have received the peer's Open message, which is acceptable, and we're waiting the acknowledgement of our
51 * The negotiation finished.
56 private static final Logger logger = LoggerFactory.getLogger(BGPSessionNegotiator.class);
57 private final BGPSessionListener listener;
58 private final Timer timer;
59 private final BGPSessionPreferences localPref;
60 private BGPOpenMessage remotePref;
61 private State state = State.Idle;
62 private final short keepAlive = 15;
64 public BGPSessionNegotiator(final Timer timer, final Promise<BGPSessionImpl> promise, final Channel channel,
65 final BGPSessionPreferences initialPrefs, final BGPSessionListener listener) {
66 super(promise, channel);
67 this.listener = Preconditions.checkNotNull(listener);
68 this.localPref = Preconditions.checkNotNull(initialPrefs);
69 this.timer = Preconditions.checkNotNull(timer);
73 protected void startNegotiation() {
74 Preconditions.checkState(this.state == State.Idle);
75 this.channel.writeAndFlush(new BGPOpenMessage(this.localPref.getMyAs(), (short) this.localPref.getHoldTime(), this.localPref.getBgpId(), this.localPref.getParams()));
76 this.state = State.OpenSent;
78 final Object lock = this;
79 this.timer.newTimeout(new TimerTask() {
81 public void run(final Timeout timeout) throws Exception {
83 if (BGPSessionNegotiator.this.state != State.Finished) {
84 negotiationFailed(new BGPDocumentedException("HoldTimer expired", BGPError.FSM_ERROR));
85 BGPSessionNegotiator.this.state = State.Finished;
89 }, INITIAL_HOLDTIMER, TimeUnit.MINUTES);
93 protected synchronized void handleMessage(final BGPMessage msg) {
94 logger.debug("Channel {} handling message in state {}", this.channel, this.state);
99 throw new IllegalStateException("Unexpected state " + this.state);
101 if (msg instanceof BGPKeepAliveMessage) {
102 final BGPKeepAliveMessage ka = (BGPKeepAliveMessage) msg;
104 // FIXME: we miss some stuff over here
106 negotiationSuccessful(new BGPSessionImpl(this.timer, this.listener, this.channel, this.keepAlive, this.remotePref));
107 this.state = State.Finished;
109 } else if (msg instanceof BGPNotificationMessage) {
110 final BGPNotificationMessage ntf = (BGPNotificationMessage) msg;
111 negotiationFailed(new BGPDocumentedException("Peer refusal", ntf.getError()));
112 this.state = State.Finished;
118 if (msg instanceof BGPOpenMessage) {
119 final BGPOpenMessage open = (BGPOpenMessage) msg;
121 // TODO: validate the open message
123 this.remotePref = open;
124 this.channel.writeAndFlush(new BGPKeepAliveMessage());
125 this.state = State.OpenConfirm;
126 logger.debug("Channel {} moved to OpenConfirm state with remote proposal {}", this.channel, this.remotePref);
132 // Catch-all for unexpected message
133 logger.warn("Channel {} state {} unexpected message {}", this.channel, this.state, msg);
134 this.channel.writeAndFlush(new BGPNotificationMessage(BGPError.FSM_ERROR));
135 negotiationFailed(new BGPDocumentedException("Unexpected message", BGPError.FSM_ERROR));
136 this.state = State.Finished;