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