df1e3e555c5387f634b29c9ac9d0517bccce940b
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / BGPPeer.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.bgp.rib.impl;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.MoreObjects;
13 import com.google.common.base.MoreObjects.ToStringHelper;
14 import com.google.common.base.Objects;
15 import com.google.common.cache.CacheBuilder;
16 import com.google.common.cache.CacheLoader;
17 import com.google.common.cache.LoadingCache;
18 import com.google.common.collect.ImmutableMap;
19 import com.google.common.collect.ImmutableSet;
20 import com.google.common.net.InetAddresses;
21 import com.google.common.util.concurrent.ListenableFuture;
22 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Optional;
30 import java.util.Set;
31 import java.util.stream.Collectors;
32 import javax.annotation.concurrent.GuardedBy;
33 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
34 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
35 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
36 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
37 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
38 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
39 import org.opendaylight.protocol.bgp.parser.BGPError;
40 import org.opendaylight.protocol.bgp.parser.impl.message.update.LocalPreferenceAttributeParser;
41 import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
43 import org.opendaylight.protocol.bgp.rib.impl.state.BGPSessionStateProvider;
44 import org.opendaylight.protocol.bgp.rib.spi.BGPSession;
45 import org.opendaylight.protocol.bgp.rib.spi.BGPSessionListener;
46 import org.opendaylight.protocol.bgp.rib.spi.BGPTerminationReason;
47 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
48 import org.opendaylight.protocol.bgp.rib.spi.RouterIds;
49 import org.opendaylight.protocol.bgp.rib.spi.state.BGPSessionState;
50 import org.opendaylight.protocol.bgp.rib.spi.state.BGPTimersState;
51 import org.opendaylight.protocol.bgp.rib.spi.state.BGPTransportState;
52 import org.opendaylight.protocol.concepts.AbstractRegistration;
53 import org.opendaylight.protocol.util.Ipv4Util;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.DestinationIpv4Builder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationIpv4CaseBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.Update;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.update.message.Nlri;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpAddPathTableType;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.RouteRefresh;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.SendReceive;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamilies;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlri;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlriBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlri;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlriBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev180329.BgpPeerRpcService;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev180329.PeerContext;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.PeerKey;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.peer.AdjRibOut;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.AddressFamily;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.ClusterIdentifier;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.Ipv4AddressFamily;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.SubsequentAddressFamily;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.UnicastSubsequentAddressFamily;
87 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
88 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
89 import org.opendaylight.yangtools.yang.binding.Notification;
90 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
91 import org.slf4j.Logger;
92 import org.slf4j.LoggerFactory;
93
94 /**
95  * Class representing a peer. We have a single instance for each peer, which provides translation from BGP events into
96  * RIB actions.
97  */
98 public class BGPPeer extends AbstractPeer implements BGPSessionListener {
99     private static final Logger LOG = LoggerFactory.getLogger(BGPPeer.class);
100
101     private Set<TablesKey> tables = Collections.emptySet();
102     private final RIB rib;
103     private final Map<TablesKey, AdjRibOutListener> adjRibOutListenerSet = new HashMap<>();
104     private final RpcProviderRegistry rpcRegistry;
105     private InstanceIdentifier<AdjRibOut> peerRibOutIId;
106     @GuardedBy("this")
107     private AbstractRegistration trackerRegistration;
108     private final LoadingCache<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>> tablesIId
109             = CacheBuilder.newBuilder()
110             .build(new CacheLoader<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>>() {
111                 @Override
112                 public KeyedInstanceIdentifier<Tables, TablesKey> load(final TablesKey tablesKey) {
113                     return BGPPeer.this.peerRibOutIId.child(Tables.class, tablesKey);
114                 }
115             });
116
117     @GuardedBy("this")
118     private BGPSession session;
119     @GuardedBy("this")
120     private DOMTransactionChain chain;
121     @GuardedBy("this")
122     private AdjRibInWriter ribWriter;
123     @GuardedBy("this")
124     private EffectiveRibInWriter effRibInWriter;
125     private RoutedRpcRegistration<BgpPeerRpcService> rpcRegistration;
126     private Map<TablesKey, SendReceive> addPathTableMaps = Collections.emptyMap();
127     private YangInstanceIdentifier peerPath;
128     private boolean sessionUp;
129
130     public BGPPeer(
131             final IpAddress neighborAddress,
132             final String peerGroupName,
133             final RIB rib,
134             final PeerRole role,
135             final ClusterIdentifier clusterId,
136             final AsNumber localAs,
137             final RpcProviderRegistry rpcRegistry,
138             final Set<TablesKey> afiSafisAdvertized,
139             final Set<TablesKey> afiSafisGracefulAdvertized) {
140         super(rib, Ipv4Util.toStringIP(neighborAddress), peerGroupName, role, clusterId,
141                 localAs, neighborAddress, afiSafisAdvertized, afiSafisGracefulAdvertized);
142         this.rib = requireNonNull(rib);
143         this.rpcRegistry = rpcRegistry;
144         this.chain = rib.createPeerDOMChain(this);
145     }
146
147     BGPPeer(
148             final IpAddress neighborAddress,
149             final RIB rib,
150             final PeerRole role,
151             final RpcProviderRegistry rpcRegistry,
152             final Set<TablesKey> afiSafisAdvertized,
153             final Set<TablesKey> afiSafisGracefulAdvertized) {
154         this(neighborAddress, null, rib, role, null, null, rpcRegistry, afiSafisAdvertized,
155                 afiSafisGracefulAdvertized);
156     }
157
158
159     private static Attributes nextHopToAttribute(final Attributes attrs, final MpReachNlri mpReach) {
160         if (attrs.getCNextHop() == null && mpReach.getCNextHop() != null) {
161             final AttributesBuilder attributesBuilder = new AttributesBuilder(attrs);
162             attributesBuilder.setCNextHop(mpReach.getCNextHop());
163             return attributesBuilder.build();
164         }
165         return attrs;
166     }
167
168     /**
169      * Creates MPReach for the prefixes to be handled in the same way as linkstate routes.
170      *
171      * @param message Update message containing prefixes in NLRI
172      * @return MpReachNlri with prefixes from the nlri field
173      */
174     private static MpReachNlri prefixesToMpReach(final Update message) {
175         final List<Ipv4Prefixes> prefixes = message.getNlri().stream()
176                 .map(n -> new Ipv4PrefixesBuilder().setPrefix(n.getPrefix()).setPathId(n.getPathId()).build())
177                 .collect(Collectors.toList());
178         final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
179                 UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
180                 new AdvertizedRoutesBuilder().setDestinationType(
181                         new DestinationIpv4CaseBuilder().setDestinationIpv4(
182                                 new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
183         if (message.getAttributes() != null) {
184             b.setCNextHop(message.getAttributes().getCNextHop());
185         }
186         return b.build();
187     }
188
189     /**
190      * Create MPUnreach for the prefixes to be handled in the same way as linkstate routes.
191      *
192      * @param message            Update message containing withdrawn routes
193      * @param isAnyNlriAnnounced isAnyNlriAnnounced
194      * @return MpUnreachNlri with prefixes from the withdrawn routes field
195      */
196     private static MpUnreachNlri prefixesToMpUnreach(final Update message, final boolean isAnyNlriAnnounced) {
197         final List<Ipv4Prefixes> prefixes = new ArrayList<>();
198         message.getWithdrawnRoutes().forEach(w -> {
199
200             Optional<Nlri> nlriAnounced = Optional.empty();
201             if (isAnyNlriAnnounced) {
202                 nlriAnounced = message.getNlri().stream().filter(n -> Objects.equal(n.getPrefix(), w.getPrefix())
203                         && Objects.equal(n.getPathId(), w.getPathId()))
204                         .findAny();
205             }
206             if (!nlriAnounced.isPresent()) {
207                 prefixes.add(new Ipv4PrefixesBuilder().setPrefix(w.getPrefix()).setPathId(w.getPathId()).build());
208             }
209         });
210         return new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class)
211                 .setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(new org.opendaylight.yang.gen.v1
212                         .urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update.attributes.mp.unreach.nlri
213                         .withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
214                         new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build();
215     }
216
217     private static Map<TablesKey, SendReceive> mapTableTypesFamilies(final List<AddressFamilies> addPathTablesType) {
218         return ImmutableMap.copyOf(addPathTablesType.stream().collect(Collectors.toMap(af -> new TablesKey(af.getAfi(),
219                         af.getSafi()), BgpAddPathTableType::getSendReceive)));
220     }
221
222     public synchronized void instantiateServiceInstance() {
223         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.chain);
224         setActive(true);
225     }
226
227     // FIXME ListenableFuture<?> should be used once closeServiceInstance uses wildcard too
228     @Override
229     public synchronized ListenableFuture<Void> close() {
230         final ListenableFuture<Void> future = releaseConnection();
231         this.chain.close();
232         setActive(false);
233         return future;
234     }
235
236     @Override
237     public void onMessage(final BGPSession session, final Notification msg) throws BGPDocumentedException {
238         if (!(msg instanceof Update) && !(msg instanceof RouteRefresh)) {
239             LOG.info("Ignoring unhandled message class {}", msg.getClass());
240             return;
241         }
242         if (msg instanceof Update) {
243             onUpdateMessage((Update) msg);
244         } else {
245             onRouteRefreshMessage((RouteRefresh) msg);
246         }
247     }
248
249     private void onRouteRefreshMessage(final RouteRefresh message) {
250         final Class<? extends AddressFamily> rrAfi = message.getAfi();
251         final Class<? extends SubsequentAddressFamily> rrSafi = message.getSafi();
252
253         final TablesKey key = new TablesKey(rrAfi, rrSafi);
254         final AdjRibOutListener listener = this.adjRibOutListenerSet.get(key);
255         if (listener != null) {
256             listener.close();
257             this.adjRibOutListenerSet.remove(key);
258             createAdjRibOutListener(key, listener.isMpSupported());
259         } else {
260             LOG.info("Ignoring RouteRefresh message. Afi/Safi is not supported: {}, {}.", rrAfi, rrSafi);
261         }
262     }
263
264     /**
265      * Check for presence of well known mandatory attribute LOCAL_PREF in Update message.
266      *
267      * @param message Update message
268      */
269     private void checkMandatoryAttributesPresence(final Update message) throws BGPDocumentedException {
270         if (MessageUtil.isAnyNlriPresent(message)) {
271             final Attributes attrs = message.getAttributes();
272             if (this.peerRole == PeerRole.Ibgp && (attrs == null || attrs.getLocalPref() == null)) {
273                 throw new BGPDocumentedException(BGPError.MANDATORY_ATTR_MISSING_MSG + "LOCAL_PREF",
274                         BGPError.WELL_KNOWN_ATTR_MISSING,
275                         new byte[]{LocalPreferenceAttributeParser.TYPE});
276             }
277         }
278     }
279
280     /**
281      * Process Update message received.
282      * Calls {@link #checkMandatoryAttributesPresence(Update)} to check for presence of mandatory attributes.
283      *
284      * @param message Update message
285      */
286     private synchronized void onUpdateMessage(final Update message) throws BGPDocumentedException {
287         checkMandatoryAttributesPresence(message);
288
289         // update AdjRibs
290         final Attributes attrs = message.getAttributes();
291         MpReachNlri mpReach;
292         final boolean isAnyNlriAnnounced = message.getNlri() != null;
293         if (isAnyNlriAnnounced) {
294             mpReach = prefixesToMpReach(message);
295         } else {
296             mpReach = MessageUtil.getMpReachNlri(attrs);
297         }
298         if (mpReach != null) {
299             this.ribWriter.updateRoutes(mpReach, nextHopToAttribute(attrs, mpReach));
300         }
301         MpUnreachNlri mpUnreach;
302         if (message.getWithdrawnRoutes() != null) {
303             mpUnreach = prefixesToMpUnreach(message, isAnyNlriAnnounced);
304         } else {
305             mpUnreach = MessageUtil.getMpUnreachNlri(attrs);
306         }
307         if (mpUnreach != null) {
308             this.ribWriter.removeRoutes(mpUnreach);
309         }
310     }
311
312     @Override
313     public synchronized void onSessionUp(final BGPSession session) {
314         this.session = session;
315         this.sessionUp = true;
316         if (this.session instanceof BGPSessionStateProvider) {
317             ((BGPSessionStateProvider) this.session).registerMessagesCounter(this);
318         }
319
320         final List<AddressFamilies> addPathTablesType = session.getAdvertisedAddPathTableTypes();
321         final Set<BgpTableType> advertizedTableTypes = session.getAdvertisedTableTypes();
322         final List<BgpTableType> advertizedGracefulRestartTableTypes = session.getAdvertisedGracefulRestartTableTypes();
323         LOG.info("Session with peer {} went up with tables {} and Add Path tables {}", this.name,
324                 advertizedTableTypes, addPathTablesType);
325         this.rawIdentifier = InetAddresses.forString(session.getBgpId().getValue()).getAddress();
326         this.peerId = RouterIds.createPeerId(session.getBgpId());
327         final KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib
328                 .rev180329.bgp.rib.rib.Peer, PeerKey> peerIId =
329                 getInstanceIdentifier().child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns
330                 .yang.bgp.rib.rev180329.bgp.rib.rib.Peer.class, new PeerKey(this.peerId));
331         final Set<TablesKey> setTables = advertizedTableTypes.stream().map(t -> new TablesKey(t.getAfi(), t.getSafi()))
332                 .collect(Collectors.toSet());
333         this.tables = ImmutableSet.copyOf(setTables);
334         this.effRibInWriter = new EffectiveRibInWriter(this, this.rib, this.rib.createPeerChain(this),
335                 peerIId, this.tables);
336         registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter);
337         this.peerRibOutIId = peerIId.child(AdjRibOut.class);
338         this.effRibInWriter.init();
339         setAdvertizedGracefulRestartTableTypes(advertizedGracefulRestartTableTypes.stream()
340                 .map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toList()));
341         this.addPathTableMaps = ImmutableMap.copyOf(mapTableTypesFamilies(addPathTablesType));
342         this.trackerRegistration = this.rib.getPeerTracker().registerPeer(this);
343
344         for (final TablesKey key : this.tables) {
345             createAdjRibOutListener(key, true);
346         }
347
348         addBgp4Support();
349
350         this.peerPath = createPeerPath();
351         this.ribWriter = this.ribWriter.transform(this.peerId, this.peerPath, this.rib.getRibSupportContext(),
352                 this.tables, this.addPathTableMaps);
353
354         if (this.rpcRegistry != null) {
355             this.rpcRegistration = this.rpcRegistry.addRoutedRpcImplementation(BgpPeerRpcService.class,
356                     new BgpPeerRpc(this, session, this.tables));
357             final KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib
358                     .rev180329.bgp.rib.rib.Peer, PeerKey> path = this.rib.getInstanceIdentifier()
359                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib
360                              .rib.Peer.class, new PeerKey(this.peerId));
361             this.rpcRegistration.registerPath(PeerContext.class, path);
362         }
363     }
364
365     //try to add a support for old-school BGP-4, if peer did not advertise IPv4-Unicast MP capability
366     private synchronized void addBgp4Support() {
367         final TablesKey key = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
368         if (!this.tables.contains(key)) {
369             final HashSet<TablesKey> newSet = new HashSet<>(this.tables);
370             newSet.add(key);
371             this.tables = ImmutableSet.copyOf(newSet);
372             createAdjRibOutListener(key, false);
373         }
374     }
375
376     private synchronized void createAdjRibOutListener(final TablesKey key,
377             final boolean mpSupport) {
378         final RIBSupport ribSupport = this.rib.getRibSupportContext().getRIBSupport(key);
379
380         // not particularly nice
381         if (ribSupport != null && this.session instanceof BGPSessionImpl) {
382             final ChannelOutputLimiter limiter = ((BGPSessionImpl) this.session).getLimiter();
383             final AdjRibOutListener adjRibOut = AdjRibOutListener.create(this.peerId, key,
384                     this.rib.getYangRibId(), this.rib.getCodecsRegistry(), ribSupport,
385                     this.rib.getService(), limiter, mpSupport);
386             this.adjRibOutListenerSet.put(key, adjRibOut);
387             registerPrefixesSentCounter(key, adjRibOut);
388         }
389     }
390
391     @SuppressFBWarnings(value = "NP_NONNULL_PARAM_VIOLATION", justification = "Unrecognised NullableDecl")
392     private synchronized ListenableFuture<Void> cleanup() {
393         // FIXME: BUG-196: support graceful
394         this.adjRibOutListenerSet.values().forEach(AdjRibOutListener::close);
395         this.adjRibOutListenerSet.clear();
396         if (this.effRibInWriter != null) {
397             this.effRibInWriter.close();
398         }
399         this.tables = Collections.emptySet();
400         this.addPathTableMaps = Collections.emptyMap();
401         return removePeer(this.chain, this.peerPath);
402     }
403
404     @Override
405     public synchronized void onSessionDown(final BGPSession session, final Exception e) {
406         if (e.getMessage().equals(BGPSessionImpl.END_OF_INPUT)) {
407             LOG.info("Session with peer {} went down", this.name);
408         } else {
409             LOG.info("Session with peer {} went down", this.name, e);
410         }
411         releaseConnection();
412     }
413
414     @Override
415     public synchronized void onSessionTerminated(final BGPSession session, final BGPTerminationReason cause) {
416         LOG.info("Session with peer {} terminated: {}", this.name, cause);
417         releaseConnection();
418     }
419
420     @Override
421     public String toString() {
422         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
423     }
424
425     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
426         toStringHelper.add("name", this.name);
427         toStringHelper.add("tables", this.tables);
428         return toStringHelper;
429     }
430
431     @Override
432     public synchronized ListenableFuture<Void> releaseConnection() {
433         LOG.info("Closing session with peer");
434         this.sessionUp = false;
435         closeRegistration();
436         if (this.rpcRegistration != null) {
437             this.rpcRegistration.close();
438         }
439         final ListenableFuture<Void> future = cleanup();
440
441         if (this.session != null) {
442             try {
443                 this.session.close();
444             } catch (final Exception e) {
445                 LOG.warn("Error closing session with peer", e);
446             }
447             this.session = null;
448         }
449         resetState();
450         return future;
451     }
452
453     private synchronized void closeRegistration() {
454         if (this.trackerRegistration != null) {
455             this.trackerRegistration.close();
456             this.trackerRegistration = null;
457         }
458     }
459
460     @SuppressFBWarnings("IS2_INCONSISTENT_SYNC")
461     @Override
462     public SendReceive getSupportedAddPathTables(final TablesKey tableKey) {
463         return this.addPathTableMaps.get(tableKey);
464     }
465
466     @Override
467     public boolean supportsTable(final TablesKey tableKey) {
468         return this.tables.contains(tableKey) && this.sessionUp;
469     }
470
471     @Override
472     public KeyedInstanceIdentifier<Tables, TablesKey> getRibOutIId(final TablesKey tablesKey) {
473         return this.tablesIId.getUnchecked(tablesKey);
474     }
475
476     @Override
477     public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
478             final AsyncTransaction<?, ?> transaction, final Throwable cause) {
479         LOG.error("Transaction chain failed.", cause);
480         this.chain.close();
481         //FIXME BGPCEP-731
482         /*
483         this.chain = this.rib.createPeerDOMChain(this);
484         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.chain);
485         releaseConnection();*/
486     }
487
488     @Override
489     public synchronized void markUptodate(final TablesKey tablesKey) {
490         this.ribWriter.markTableUptodate(tablesKey);
491     }
492
493     @Override
494     public synchronized BGPSessionState getBGPSessionState() {
495         if (this.session instanceof BGPSessionStateProvider) {
496             return ((BGPSessionStateProvider) this.session).getBGPSessionState();
497         }
498         return null;
499     }
500
501     @Override
502     public synchronized BGPTimersState getBGPTimersState() {
503         if (this.session instanceof BGPSessionStateProvider) {
504             return ((BGPSessionStateProvider) this.session).getBGPTimersState();
505         }
506         return null;
507     }
508
509     @Override
510     public synchronized BGPTransportState getBGPTransportState() {
511         if (this.session instanceof BGPSessionStateProvider) {
512             return ((BGPSessionStateProvider) this.session).getBGPTransportState();
513         }
514         return null;
515     }
516 }