try {
final BGPSessionListener peer = this.registry.getPeer(getRemoteIp(), getSourceId(openObj, getPreferences()), getDestinationId(openObj, getPreferences()));
this.sendMessage(new KeepaliveBuilder().build());
- this.session = new BGPSessionImpl(peer, this.channel, openObj, getPreferences());
+ this.session = new BGPSessionImpl(peer, this.channel, openObj, getPreferences(), this.registry);
this.state = State.OPEN_CONFIRM;
LOG.debug("Channel {} moved to OpenConfirm state with remote proposal {}", this.channel, openObj);
} catch (final BGPDocumentedException e) {
import org.opendaylight.protocol.bgp.parser.AsNumberUtil;
import org.opendaylight.protocol.bgp.parser.BGPError;
import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionStatistics;
import org.opendaylight.protocol.bgp.rib.spi.BGPSession;
private final int keepAlive;
private final AsNumber asNumber;
private final Ipv4Address bgpId;
+ private final BGPPeerRegistry peerRegistry;
+
private BGPSessionStats sessionStats;
- public BGPSessionImpl(final BGPSessionListener listener, final Channel channel, final Open remoteOpen, final BGPSessionPreferences localPreferences) {
- this(listener, channel, remoteOpen, localPreferences.getHoldTime());
+ public BGPSessionImpl(final BGPSessionListener listener, final Channel channel, final Open remoteOpen, final BGPSessionPreferences localPreferences,
+ final BGPPeerRegistry peerRegitry) {
+ this(listener, channel, remoteOpen, localPreferences.getHoldTime(), peerRegitry);
this.sessionStats = new BGPSessionStats(remoteOpen, this.holdTimerValue, this.keepAlive, channel, Optional.of(localPreferences), this.tableTypes);
}
- public BGPSessionImpl(final BGPSessionListener listener, final Channel channel, final Open remoteOpen, final int localHoldTimer) {
+ public BGPSessionImpl(final BGPSessionListener listener, final Channel channel, final Open remoteOpen, final int localHoldTimer,
+ final BGPPeerRegistry peerRegitry) {
this.listener = Preconditions.checkNotNull(listener);
this.channel = Preconditions.checkNotNull(channel);
this.holdTimerValue = (remoteOpen.getHoldTimer() < localHoldTimer) ? remoteOpen.getHoldTimer() : localHoldTimer;
LOG.info("BGP HoldTimer new value: {}", this.holdTimerValue);
this.keepAlive = this.holdTimerValue / KA_TO_DEADTIMER_RATIO;
this.asNumber = AsNumberUtil.advertizedAsNumber(remoteOpen);
+ this.peerRegistry = peerRegitry;
final Set<TablesKey> tts = Sets.newHashSet();
final Set<BgpTableType> tats = Sets.newHashSet();
@Override
public synchronized void close() {
LOG.info("Closing session: {}", this);
+
if (this.state != State.IDLE) {
this.sendMessage(new NotifyBuilder().setErrorCode(BGPError.CEASE.getCode()).setErrorSubcode(
BGPError.CEASE.getSubcode()).build());
+ removePeerSession();
this.channel.close();
this.state = State.IDLE;
}
private synchronized void closeWithoutMessage() {
LOG.debug("Closing session: {}", this);
+ removePeerSession();
this.channel.close();
this.state = State.IDLE;
}
this.listener.onSessionTerminated(this, new BGPTerminationReason(error));
}
+ private void removePeerSession() {
+ if (this.peerRegistry != null) {
+ this.peerRegistry.removePeerSession(StrictBGPPeerRegistry.getIpAddress(this.channel.remoteAddress()));
+ }
+ }
+
/**
* If HoldTimer expires, the session ends. If a message (whichever) was received during this period, the HoldTimer
* will be rescheduled by HOLD_TIMER_VALUE + the time that has passed from the start of the HoldTimer to the time at
package org.opendaylight.protocol.bgp.rib.impl;
-import com.google.common.base.CharMatcher;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
+import com.google.common.net.InetAddresses;
+import com.google.common.primitives.UnsignedInts;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
private static final Logger LOG = LoggerFactory.getLogger(StrictBGPPeerRegistry.class);
- private static final CharMatcher NONDIGIT = CharMatcher.inRange('0', '9').negate();
-
// TODO remove backwards compatibility
public static final StrictBGPPeerRegistry GLOBAL = new StrictBGPPeerRegistry();
this.peers.remove(ip);
}
+ @Override
public synchronized void removePeerSession(final IpAddress ip) {
Preconditions.checkNotNull(ip);
this.sessionIds.remove(ip);
final BGPSessionId currentConnection = new BGPSessionId(sourceId, remoteId);
final BGPSessionListener p = this.peers.get(ip);
- if (this.sessionIds.containsKey(ip)) {
- if (p.isSessionActive()) {
-
- LOG.warn("Duplicate BGP session established with {}", ip);
-
- final BGPSessionId previousConnection = this.sessionIds.get(ip);
-
- // Session reestablished with different ids
- if (!previousConnection.equals(currentConnection)) {
- LOG.warn("BGP session with {} {} has to be dropped. Same session already present {}", ip, currentConnection, previousConnection);
- throw new BGPDocumentedException(
- String.format("BGP session with %s %s has to be dropped. Same session already present %s",
- ip, currentConnection, previousConnection),
- BGPError.CEASE);
-
- // Session reestablished with lower source bgp id, dropping current
- } else if (previousConnection.isHigherDirection(currentConnection)) {
- LOG.warn("BGP session with {} {} has to be dropped. Opposite session already present", ip, currentConnection);
- throw new BGPDocumentedException(
- String.format("BGP session with %s initiated %s has to be dropped. Opposite session already present",
- ip, currentConnection),
- BGPError.CEASE);
-
- // Session reestablished with higher source bgp id, dropping previous
- } else if (currentConnection.isHigherDirection(previousConnection)) {
- LOG.warn("BGP session with {} {} released. Replaced by opposite session", ip, previousConnection);
- this.peers.get(ip).releaseConnection();
- return this.peers.get(ip);
-
- // Session reestablished with same source bgp id, dropping current as duplicate
- } else {
- LOG.warn("BGP session with %s initiated from %s to %s has to be dropped. Same session already present", ip, sourceId, remoteId);
- throw new BGPDocumentedException(
- String.format("BGP session with %s initiated %s has to be dropped. Same session already present",
- ip, currentConnection),
- BGPError.CEASE);
- }
+ final BGPSessionId previousConnection = this.sessionIds.get(ip);
+
+ if (previousConnection != null) {
+
+ LOG.warn("Duplicate BGP session established with {}", ip);
+
+ // Session reestablished with different ids
+ if (!previousConnection.equals(currentConnection)) {
+ LOG.warn("BGP session with {} {} has to be dropped. Same session already present {}", ip, currentConnection, previousConnection);
+ throw new BGPDocumentedException(
+ String.format("BGP session with %s %s has to be dropped. Same session already present %s",
+ ip, currentConnection, previousConnection),
+ BGPError.CEASE);
+
+ // Session reestablished with lower source bgp id, dropping current
+ } else if (previousConnection.isHigherDirection(currentConnection)) {
+ LOG.warn("BGP session with {} {} has to be dropped. Opposite session already present", ip, currentConnection);
+ throw new BGPDocumentedException(
+ String.format("BGP session with %s initiated %s has to be dropped. Opposite session already present",
+ ip, currentConnection),
+ BGPError.CEASE);
+
+ // Session reestablished with higher source bgp id, dropping previous
+ } else if (currentConnection.isHigherDirection(previousConnection)) {
+ LOG.warn("BGP session with {} {} released. Replaced by opposite session", ip, previousConnection);
+ this.peers.get(ip).releaseConnection();
+ return this.peers.get(ip);
+
+ // Session reestablished with same source bgp id, dropping current as duplicate
} else {
- removePeerSession(ip);
+ LOG.warn("BGP session with %s initiated from %s to %s has to be dropped. Same session already present", ip, sourceId, remoteId);
+ throw new BGPDocumentedException(
+ String.format("BGP session with %s initiated %s has to be dropped. Same session already present",
+ ip, currentConnection),
+ BGPError.CEASE);
}
}
* Session identifier that contains (source Bgp Id) -> (destination Bgp Id)
*/
private static final class BGPSessionId {
+
private final Ipv4Address from, to;
BGPSessionId(final Ipv4Address from, final Ipv4Address to) {
* Check if this connection is equal to other and if it contains higher source bgp id
*/
boolean isHigherDirection(final BGPSessionId other) {
- Preconditions.checkState(!this.isSameDirection(other), "Equal sessions with same direction");
return toLong(this.from) > toLong(other.from);
}
private long toLong(final Ipv4Address from) {
- return Long.parseLong(NONDIGIT.removeFrom(from.getValue()));
- }
-
- /**
- * Check if 2 connections are equal and face same direction
- */
- boolean isSameDirection(final BGPSessionId other) {
- Preconditions.checkState(this.equals(other), "Only equal sessions can be compared");
- return this.from.equals(other.from);
+ final int i = InetAddresses.coerceToInteger(InetAddresses.forString(from.getValue()));
+ return UnsignedInts.toLong(i);
}
@Override
Mockito.doReturn(null).when(this.eventLoop).schedule(any(Runnable.class), any(long.class), any(TimeUnit.class));
Mockito.doReturn(Boolean.TRUE).when(this.channel).isWritable();
Mockito.doReturn(null).when(this.channel).close();
+
Mockito.doReturn(new InetSocketAddress("localhost", 12345)).when(this.channel).remoteAddress();
Mockito.doReturn(new InetSocketAddress("localhost", 12345)).when(this.channel).localAddress();
final List<BgpParameters> params = Lists.newArrayList(new BgpParametersBuilder().setOptionalCapabilities(Lists.newArrayList(new OptionalCapabilitiesBuilder().setCParameters(new MultiprotocolCaseBuilder()
.setMultiprotocolCapability(new MultiprotocolCapabilityBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).build()).build()).build())).build());
- this.session = new BGPSessionImpl(this.classic, this.channel, new OpenBuilder().setBgpIdentifier(new Ipv4Address("1.1.1.1")).setHoldTimer(50).setMyAsNumber(72).setBgpParameters(params).build(), 30);
+ this.session = new BGPSessionImpl(this.classic, this.channel, new OpenBuilder().setBgpIdentifier(new Ipv4Address("1.1.1.1")).setHoldTimer(50).setMyAsNumber(72).setBgpParameters(params).build(), 30, null);
assertEquals(this.r, this.classic.getRib());
assertEquals("testPeer", this.classic.getName());
Mockito.doAnswer(new Answer<Object>() {
final BGPSessionPreferences prefs = new BGPSessionPreferences(AS_NUMBER, (short) 90, new Ipv4Address(ADDRESS.getAddress().getHostAddress()), tlvs);
Mockito.doReturn(true).when(this.registry).isPeerConfigured(Mockito.any(IpAddress.class));
Mockito.doReturn(prefs).when(this.registry).getPeerPreferences(Mockito.any(IpAddress.class));
+ Mockito.doNothing().when(this.registry).removePeerSession(Mockito.any(IpAddress.class));
Mockito.doReturn(this.sessionListener).when(this.registry).getPeer(Mockito.any(IpAddress.class), Mockito.any(Ipv4Address.class), Mockito.any(Ipv4Address.class));
this.dispatcher = new BGPDispatcherImpl(ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getMessageRegistry(), group, group);
doReturn(this.pipeline).when(this.pipeline).replace(any(ChannelHandler.class), any(String.class), any(ChannelHandler.class));
doReturn(mock(ChannelFuture.class)).when(this.speakerListener).close();
this.listener = new SimpleSessionListener();
- this.bgpSession = new BGPSessionImpl(this.listener, this.speakerListener, this.classicOpen, this.classicOpen.getHoldTimer());
+ this.bgpSession = new BGPSessionImpl(this.listener, this.speakerListener, this.classicOpen, this.classicOpen.getHoldTimer(), null);
}
@Test
private final BGPSessionListener client;
SpeakerSessionMock(final BGPSessionListener listener, final BGPSessionListener client) {
- super(listener, mock(Channel.class), new OpenBuilder().setHoldTimer(5).build(), 10);
+ super(listener, mock(Channel.class), new OpenBuilder().setHoldTimer(5).build(), 10, null);
this.client = client;
}
import org.junit.Test;
import org.mockito.Mockito;
import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
+import org.opendaylight.protocol.bgp.parser.BGPError;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
import org.opendaylight.protocol.bgp.rib.impl.spi.ReusableBGPPeer;
import org.opendaylight.protocol.bgp.rib.spi.BGPSessionListener;
this.droppingBGPSessionRegistry.getPeer(remoteIp, from, to);
try {
this.droppingBGPSessionRegistry.getPeer(remoteIp, from, to);
- } catch (final IllegalStateException e) {
- Mockito.verify(session1).isSessionActive();
+ } catch (final BGPDocumentedException e) {
+ assertEquals(BGPError.CEASE, e.getError());
return;
}
try {
this.droppingBGPSessionRegistry.getPeer(remoteIp, lower, higher);
} catch (final BGPDocumentedException e) {
- Mockito.verify(session1).isSessionActive();
+ assertEquals(BGPError.CEASE, e.getError());
return;
}
Mockito.verify(session1).releaseConnection();
}
+ @Test
+ public void testDuplicateDifferentIds() throws Exception {
+ final Ipv4Address from = new Ipv4Address("0.0.0.1");
+ final IpAddress remoteIp = new IpAddress(from);
+ final Ipv4Address to = new Ipv4Address("255.255.255.255");
+
+ final ReusableBGPPeer session1 = getMockSession();
+ this.droppingBGPSessionRegistry.addPeer(remoteIp, session1, this.mockPreferences);
+
+ this.droppingBGPSessionRegistry.getPeer(remoteIp, from, to);
+ try {
+ this.droppingBGPSessionRegistry.getPeer(remoteIp, to, to);
+ } catch (final BGPDocumentedException e) {
+ assertEquals(BGPError.CEASE, e.getError());
+ return;
+ }
+
+ fail("Same peer cannot be connected twice");
+ }
+
private ReusableBGPPeer getMockSession() {
final ReusableBGPPeer mock = Mockito.mock(ReusableBGPPeer.class);
Mockito.doNothing().when(mock).releaseConnection();
- Mockito.doReturn(Boolean.TRUE).when(mock).isSessionActive();
return mock;
}