Migrate deprecated submit() to commit() for BGP/BMP
[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.FluentFuture;
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.mdsal.common.api.CommitInfo;
39 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
40 import org.opendaylight.protocol.bgp.parser.BGPError;
41 import org.opendaylight.protocol.bgp.parser.impl.message.update.LocalPreferenceAttributeParser;
42 import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
44 import org.opendaylight.protocol.bgp.rib.impl.state.BGPSessionStateProvider;
45 import org.opendaylight.protocol.bgp.rib.spi.BGPSession;
46 import org.opendaylight.protocol.bgp.rib.spi.BGPSessionListener;
47 import org.opendaylight.protocol.bgp.rib.spi.BGPTerminationReason;
48 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
49 import org.opendaylight.protocol.bgp.rib.spi.RouterIds;
50 import org.opendaylight.protocol.bgp.rib.spi.state.BGPSessionState;
51 import org.opendaylight.protocol.bgp.rib.spi.state.BGPTimersState;
52 import org.opendaylight.protocol.bgp.rib.spi.state.BGPTransportState;
53 import org.opendaylight.protocol.concepts.AbstractRegistration;
54 import org.opendaylight.protocol.util.Ipv4Util;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.DestinationIpv4Builder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder;
60 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;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.Update;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.update.message.Nlri;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpAddPathTableType;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.RouteRefresh;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.SendReceive;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamilies;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlri;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlriBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlri;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlriBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev180329.BgpPeerRpcService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev180329.PeerContext;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.PeerKey;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.peer.AdjRibOut;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.AddressFamily;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.ClusterIdentifier;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.Ipv4AddressFamily;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.SubsequentAddressFamily;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.UnicastSubsequentAddressFamily;
88 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
89 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
90 import org.opendaylight.yangtools.yang.binding.Notification;
91 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
92 import org.slf4j.Logger;
93 import org.slf4j.LoggerFactory;
94
95 /**
96  * Class representing a peer. We have a single instance for each peer, which provides translation from BGP events into
97  * RIB actions.
98  */
99 public class BGPPeer extends AbstractPeer implements BGPSessionListener {
100     private static final Logger LOG = LoggerFactory.getLogger(BGPPeer.class);
101
102     private Set<TablesKey> tables = Collections.emptySet();
103     private final RIB rib;
104     private final Map<TablesKey, AdjRibOutListener> adjRibOutListenerSet = new HashMap<>();
105     private final RpcProviderRegistry rpcRegistry;
106     private InstanceIdentifier<AdjRibOut> peerRibOutIId;
107     @GuardedBy("this")
108     private AbstractRegistration trackerRegistration;
109     private final LoadingCache<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>> tablesIId
110             = CacheBuilder.newBuilder()
111             .build(new CacheLoader<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>>() {
112                 @Override
113                 public KeyedInstanceIdentifier<Tables, TablesKey> load(final TablesKey tablesKey) {
114                     return BGPPeer.this.peerRibOutIId.child(Tables.class, tablesKey);
115                 }
116             });
117
118     @GuardedBy("this")
119     private BGPSession session;
120     @GuardedBy("this")
121     private DOMTransactionChain chain;
122     @GuardedBy("this")
123     private AdjRibInWriter ribWriter;
124     @GuardedBy("this")
125     private EffectiveRibInWriter effRibInWriter;
126     private RoutedRpcRegistration<BgpPeerRpcService> rpcRegistration;
127     private Map<TablesKey, SendReceive> addPathTableMaps = Collections.emptyMap();
128     private YangInstanceIdentifier peerPath;
129     private boolean sessionUp;
130
131     public BGPPeer(
132             final IpAddress neighborAddress,
133             final String peerGroupName,
134             final RIB rib,
135             final PeerRole role,
136             final ClusterIdentifier clusterId,
137             final AsNumber localAs,
138             final RpcProviderRegistry rpcRegistry,
139             final Set<TablesKey> afiSafisAdvertized,
140             final Set<TablesKey> afiSafisGracefulAdvertized) {
141         super(rib, Ipv4Util.toStringIP(neighborAddress), peerGroupName, role, clusterId,
142                 localAs, neighborAddress, afiSafisAdvertized, afiSafisGracefulAdvertized);
143         this.rib = requireNonNull(rib);
144         this.rpcRegistry = rpcRegistry;
145         this.chain = rib.createPeerDOMChain(this);
146     }
147
148     BGPPeer(
149             final IpAddress neighborAddress,
150             final RIB rib,
151             final PeerRole role,
152             final RpcProviderRegistry rpcRegistry,
153             final Set<TablesKey> afiSafisAdvertized,
154             final Set<TablesKey> afiSafisGracefulAdvertized) {
155         this(neighborAddress, null, rib, role, null, null, rpcRegistry, afiSafisAdvertized,
156                 afiSafisGracefulAdvertized);
157     }
158
159
160     private static Attributes nextHopToAttribute(final Attributes attrs, final MpReachNlri mpReach) {
161         if (attrs.getCNextHop() == null && mpReach.getCNextHop() != null) {
162             final AttributesBuilder attributesBuilder = new AttributesBuilder(attrs);
163             attributesBuilder.setCNextHop(mpReach.getCNextHop());
164             return attributesBuilder.build();
165         }
166         return attrs;
167     }
168
169     /**
170      * Creates MPReach for the prefixes to be handled in the same way as linkstate routes.
171      *
172      * @param message Update message containing prefixes in NLRI
173      * @return MpReachNlri with prefixes from the nlri field
174      */
175     private static MpReachNlri prefixesToMpReach(final Update message) {
176         final List<Ipv4Prefixes> prefixes = message.getNlri().stream()
177                 .map(n -> new Ipv4PrefixesBuilder().setPrefix(n.getPrefix()).setPathId(n.getPathId()).build())
178                 .collect(Collectors.toList());
179         final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
180                 UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
181                 new AdvertizedRoutesBuilder().setDestinationType(
182                         new DestinationIpv4CaseBuilder().setDestinationIpv4(
183                                 new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
184         if (message.getAttributes() != null) {
185             b.setCNextHop(message.getAttributes().getCNextHop());
186         }
187         return b.build();
188     }
189
190     /**
191      * Create MPUnreach for the prefixes to be handled in the same way as linkstate routes.
192      *
193      * @param message            Update message containing withdrawn routes
194      * @param isAnyNlriAnnounced isAnyNlriAnnounced
195      * @return MpUnreachNlri with prefixes from the withdrawn routes field
196      */
197     private static MpUnreachNlri prefixesToMpUnreach(final Update message, final boolean isAnyNlriAnnounced) {
198         final List<Ipv4Prefixes> prefixes = new ArrayList<>();
199         message.getWithdrawnRoutes().forEach(w -> {
200
201             Optional<Nlri> nlriAnounced = Optional.empty();
202             if (isAnyNlriAnnounced) {
203                 nlriAnounced = message.getNlri().stream().filter(n -> Objects.equal(n.getPrefix(), w.getPrefix())
204                         && Objects.equal(n.getPathId(), w.getPathId()))
205                         .findAny();
206             }
207             if (!nlriAnounced.isPresent()) {
208                 prefixes.add(new Ipv4PrefixesBuilder().setPrefix(w.getPrefix()).setPathId(w.getPathId()).build());
209             }
210         });
211         return new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class)
212                 .setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(new org.opendaylight.yang.gen.v1
213                         .urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update.attributes.mp.unreach.nlri
214                         .withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
215                         new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build();
216     }
217
218     private static Map<TablesKey, SendReceive> mapTableTypesFamilies(final List<AddressFamilies> addPathTablesType) {
219         return ImmutableMap.copyOf(addPathTablesType.stream().collect(Collectors.toMap(af -> new TablesKey(af.getAfi(),
220                         af.getSafi()), BgpAddPathTableType::getSendReceive)));
221     }
222
223     public synchronized void instantiateServiceInstance() {
224         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.chain);
225         setActive(true);
226     }
227
228     @Override
229     public synchronized FluentFuture<? extends CommitInfo> close() {
230         final FluentFuture<? extends CommitInfo> 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     private synchronized FluentFuture<? extends CommitInfo> cleanup() {
392         // FIXME: BUG-196: support graceful
393         this.adjRibOutListenerSet.values().forEach(AdjRibOutListener::close);
394         this.adjRibOutListenerSet.clear();
395         if (this.effRibInWriter != null) {
396             this.effRibInWriter.close();
397         }
398         this.tables = Collections.emptySet();
399         this.addPathTableMaps = Collections.emptyMap();
400         return removePeer(this.chain, this.peerPath);
401     }
402
403     @Override
404     public synchronized void onSessionDown(final BGPSession session, final Exception e) {
405         if (e.getMessage().equals(BGPSessionImpl.END_OF_INPUT)) {
406             LOG.info("Session with peer {} went down", this.name);
407         } else {
408             LOG.info("Session with peer {} went down", this.name, e);
409         }
410         releaseConnection();
411     }
412
413     @Override
414     public synchronized void onSessionTerminated(final BGPSession session, final BGPTerminationReason cause) {
415         LOG.info("Session with peer {} terminated: {}", this.name, cause);
416         releaseConnection();
417     }
418
419     @Override
420     public String toString() {
421         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
422     }
423
424     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
425         toStringHelper.add("name", this.name);
426         toStringHelper.add("tables", this.tables);
427         return toStringHelper;
428     }
429
430     @Override
431     public synchronized FluentFuture<? extends CommitInfo> releaseConnection() {
432         LOG.info("Closing session with peer");
433         this.sessionUp = false;
434         closeRegistration();
435         if (this.rpcRegistration != null) {
436             this.rpcRegistration.close();
437         }
438         final FluentFuture<? extends CommitInfo> future = cleanup();
439
440         if (this.session != null) {
441             try {
442                 this.session.close();
443             } catch (final Exception e) {
444                 LOG.warn("Error closing session with peer", e);
445             }
446             this.session = null;
447         }
448         resetState();
449         return future;
450     }
451
452     private synchronized void closeRegistration() {
453         if (this.trackerRegistration != null) {
454             this.trackerRegistration.close();
455             this.trackerRegistration = null;
456         }
457     }
458
459     @SuppressFBWarnings("IS2_INCONSISTENT_SYNC")
460     @Override
461     public SendReceive getSupportedAddPathTables(final TablesKey tableKey) {
462         return this.addPathTableMaps.get(tableKey);
463     }
464
465     @Override
466     public boolean supportsTable(final TablesKey tableKey) {
467         return this.tables.contains(tableKey) && this.sessionUp;
468     }
469
470     @Override
471     public KeyedInstanceIdentifier<Tables, TablesKey> getRibOutIId(final TablesKey tablesKey) {
472         return this.tablesIId.getUnchecked(tablesKey);
473     }
474
475     @Override
476     public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
477             final AsyncTransaction<?, ?> transaction, final Throwable cause) {
478         LOG.error("Transaction chain failed.", cause);
479         this.chain.close();
480         //FIXME BGPCEP-731
481         /*
482         this.chain = this.rib.createPeerDOMChain(this);
483         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.chain);
484         releaseConnection();*/
485     }
486
487     @Override
488     public synchronized void markUptodate(final TablesKey tablesKey) {
489         this.ribWriter.markTableUptodate(tablesKey);
490     }
491
492     @Override
493     public synchronized BGPSessionState getBGPSessionState() {
494         if (this.session instanceof BGPSessionStateProvider) {
495             return ((BGPSessionStateProvider) this.session).getBGPSessionState();
496         }
497         return null;
498     }
499
500     @Override
501     public synchronized BGPTimersState getBGPTimersState() {
502         if (this.session instanceof BGPSessionStateProvider) {
503             return ((BGPSessionStateProvider) this.session).getBGPTimersState();
504         }
505         return null;
506     }
507
508     @Override
509     public synchronized BGPTransportState getBGPTransportState() {
510         if (this.session instanceof BGPSessionStateProvider) {
511             return ((BGPSessionStateProvider) this.session).getBGPTransportState();
512         }
513         return null;
514     }
515 }