MVPN RFC6514 Extendend communities
[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         if (this.ribWriter != null) {
402             this.ribWriter = null;
403         }
404         return removePeer(this.chain, this.peerPath);
405     }
406
407     @Override
408     public synchronized void onSessionDown(final BGPSession session, final Exception e) {
409         if (e.getMessage().equals(BGPSessionImpl.END_OF_INPUT)) {
410             LOG.info("Session with peer {} went down", this.name);
411         } else {
412             LOG.info("Session with peer {} went down", this.name, e);
413         }
414         releaseConnection();
415     }
416
417     @Override
418     public synchronized void onSessionTerminated(final BGPSession session, final BGPTerminationReason cause) {
419         LOG.info("Session with peer {} terminated: {}", this.name, cause);
420         releaseConnection();
421     }
422
423     @Override
424     public String toString() {
425         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
426     }
427
428     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
429         toStringHelper.add("name", this.name);
430         toStringHelper.add("tables", this.tables);
431         return toStringHelper;
432     }
433
434     @Override
435     public synchronized ListenableFuture<Void> releaseConnection() {
436         LOG.info("Closing session with peer");
437         this.sessionUp = false;
438         closeRegistration();
439         if (this.rpcRegistration != null) {
440             this.rpcRegistration.close();
441         }
442         final ListenableFuture<Void> future = cleanup();
443
444         if (this.session != null) {
445             try {
446                 this.session.close();
447             } catch (final Exception e) {
448                 LOG.warn("Error closing session with peer", e);
449             }
450             this.session = null;
451         }
452         resetState();
453         return future;
454     }
455
456     private synchronized void closeRegistration() {
457         if (this.trackerRegistration != null) {
458             this.trackerRegistration.close();
459             this.trackerRegistration = null;
460         }
461     }
462
463     @SuppressFBWarnings("IS2_INCONSISTENT_SYNC")
464     @Override
465     public SendReceive getSupportedAddPathTables(final TablesKey tableKey) {
466         return this.addPathTableMaps.get(tableKey);
467     }
468
469     @Override
470     public boolean supportsTable(final TablesKey tableKey) {
471         return this.tables.contains(tableKey) && this.sessionUp;
472     }
473
474     @Override
475     public KeyedInstanceIdentifier<Tables, TablesKey> getRibOutIId(final TablesKey tablesKey) {
476         return this.tablesIId.getUnchecked(tablesKey);
477     }
478
479     @Override
480     public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
481             final AsyncTransaction<?, ?> transaction, final Throwable cause) {
482         LOG.error("Transaction chain failed.", cause);
483         this.chain.close();
484         //FIXME BGPCEP-731
485         /*
486         this.chain = this.rib.createPeerDOMChain(this);
487         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.chain);
488         releaseConnection();*/
489     }
490
491     @Override
492     public synchronized void markUptodate(final TablesKey tablesKey) {
493         this.ribWriter.markTableUptodate(tablesKey);
494     }
495
496     @Override
497     public synchronized BGPSessionState getBGPSessionState() {
498         if (this.session instanceof BGPSessionStateProvider) {
499             return ((BGPSessionStateProvider) this.session).getBGPSessionState();
500         }
501         return null;
502     }
503
504     @Override
505     public synchronized BGPTimersState getBGPTimersState() {
506         if (this.session instanceof BGPSessionStateProvider) {
507             return ((BGPSessionStateProvider) this.session).getBGPTimersState();
508         }
509         return null;
510     }
511
512     @Override
513     public synchronized BGPTransportState getBGPTransportState() {
514         if (this.session instanceof BGPSessionStateProvider) {
515             return ((BGPSessionStateProvider) this.session).getBGPTransportState();
516         }
517         return null;
518     }
519 }