c4134249b16bc78a31b1b2537f44942c9fdaf3dd
[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.concurrent.GuardedBy;
35 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
37 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
38 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
39 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
40 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
41 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
42 import org.opendaylight.protocol.bgp.parser.BGPError;
43 import org.opendaylight.protocol.bgp.parser.impl.message.update.LocalPreferenceAttributeParser;
44 import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
46 import org.opendaylight.protocol.bgp.rib.impl.state.BGPPeerStateImpl;
47 import org.opendaylight.protocol.bgp.rib.impl.state.BGPSessionStateProvider;
48 import org.opendaylight.protocol.bgp.rib.spi.BGPSession;
49 import org.opendaylight.protocol.bgp.rib.spi.BGPSessionListener;
50 import org.opendaylight.protocol.bgp.rib.spi.BGPTerminationReason;
51 import org.opendaylight.protocol.bgp.rib.spi.Peer;
52 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
53 import org.opendaylight.protocol.bgp.rib.spi.RouterIds;
54 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameters;
55 import org.opendaylight.protocol.bgp.rib.spi.state.BGPAfiSafiState;
56 import org.opendaylight.protocol.bgp.rib.spi.state.BGPErrorHandlingState;
57 import org.opendaylight.protocol.bgp.rib.spi.state.BGPSessionState;
58 import org.opendaylight.protocol.bgp.rib.spi.state.BGPTimersState;
59 import org.opendaylight.protocol.bgp.rib.spi.state.BGPTransportState;
60 import org.opendaylight.protocol.concepts.AbstractRegistration;
61 import org.opendaylight.protocol.util.Ipv4Util;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
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.rev180329.ipv4.prefixes.DestinationIpv4Builder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder;
67 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;
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.rev180329.BgpPeerRpcService;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev180329.PeerContext;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.PeerKey;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.peer.AdjRibOut;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.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     private final AsNumber localAs;
111
112     private Set<TablesKey> tables = Collections.emptySet();
113     private final RIB rib;
114     private final String name;
115     private final Map<TablesKey, AdjRibOutListener> adjRibOutListenerSet = new HashMap<>();
116     private final RpcProviderRegistry rpcRegistry;
117     private final PeerRole peerRole;
118     private InstanceIdentifier<AdjRibOut> peerRibOutIId;
119     private KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib
120             .rev180329.bgp.rib.rib.Peer, PeerKey> peerIId;
121     @GuardedBy("this")
122     private AbstractRegistration trackerRegistration;
123     private final LoadingCache<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>> tablesIId
124             = CacheBuilder.newBuilder()
125             .build(new CacheLoader<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>>() {
126                 @Override
127                 public KeyedInstanceIdentifier<Tables, TablesKey> load(final TablesKey tablesKey) {
128                     return BGPPeer.this.peerRibOutIId.child(Tables.class, tablesKey);
129                 }
130             });
131
132     @GuardedBy("this")
133     private BGPSession session;
134     @GuardedBy("this")
135     private byte[] rawIdentifier;
136     @GuardedBy("this")
137     private DOMTransactionChain chain;
138     @GuardedBy("this")
139     private AdjRibInWriter ribWriter;
140     @GuardedBy("this")
141     private EffectiveRibInWriter effRibInWriter;
142     private RoutedRpcRegistration<BgpPeerRpcService> rpcRegistration;
143     private Map<TablesKey, SendReceive> addPathTableMaps = Collections.emptyMap();
144     private PeerId peerId;
145
146     public BGPPeer(
147             final IpAddress neighborAddress,
148             final String peerGroupName,
149             final RIB rib,
150             final PeerRole role,
151             final ClusterIdentifier clusterId,
152             final AsNumber localAs,
153             final RpcProviderRegistry rpcRegistry,
154             final Set<TablesKey> afiSafisAdvertized,
155             final Set<TablesKey> afiSafisGracefulAdvertized) {
156         super(rib.getInstanceIdentifier(), peerGroupName, neighborAddress, afiSafisAdvertized,
157                 afiSafisGracefulAdvertized);
158         this.peerRole = role;
159         this.rib = requireNonNull(rib);
160         this.clusterId = clusterId;
161         this.localAs = localAs;
162         this.name = Ipv4Util.toStringIP(neighborAddress);
163         this.rpcRegistry = rpcRegistry;
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, 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.rev180329.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         this.peerIId = getInstanceIdentifier().child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns
346                 .yang.bgp.rib.rev180329.bgp.rib.rib.Peer.class, new PeerKey(this.peerId));
347         this.peerRibOutIId = this.peerIId.child(AdjRibOut.class);
348
349         final Set<TablesKey> setTables = advertizedTableTypes.stream().map(t -> new TablesKey(t.getAfi(), t.getSafi()))
350                 .collect(Collectors.toSet());
351         this.tables = ImmutableSet.copyOf(setTables);
352
353         setAdvertizedGracefulRestartTableTypes(advertizedGracefulRestartTableTypes.stream()
354                 .map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toList()));
355         this.addPathTableMaps = ImmutableMap.copyOf(mapTableTypesFamilies(addPathTablesType));
356         this.trackerRegistration = this.rib.getPeerTracker().registerPeer(this);
357
358         for (final TablesKey key : this.tables) {
359             createAdjRibOutListener(key, true);
360         }
361
362         addBgp4Support();
363
364         this.effRibInWriter = EffectiveRibInWriter.create(this, this.rib, this.rib.createPeerChain(this),
365                 this.peerIId, this.tables);
366
367
368         registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter);
369         this.ribWriter = this.ribWriter.transform(this.peerId, this.rib.getRibSupportContext(), this.tables,
370                 this.addPathTableMaps);
371
372         if (this.rpcRegistry != null) {
373             this.rpcRegistration = this.rpcRegistry.addRoutedRpcImplementation(BgpPeerRpcService.class,
374                     new BgpPeerRpc(this, session, this.tables));
375             final KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib
376                     .rev180329.bgp.rib.rib.Peer, PeerKey> path = this.rib.getInstanceIdentifier()
377                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib
378                              .rib.Peer.class, new PeerKey(this.peerId));
379             this.rpcRegistration.registerPath(PeerContext.class, path);
380         }
381     }
382
383     //try to add a support for old-school BGP-4, if peer did not advertise IPv4-Unicast MP capability
384     private synchronized void addBgp4Support() {
385         final TablesKey key = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
386         if (!this.tables.contains(key)) {
387             final HashSet<TablesKey> newSet = new HashSet<>(this.tables);
388             newSet.add(key);
389             this.tables = ImmutableSet.copyOf(newSet);
390             createAdjRibOutListener(key, false);
391         }
392     }
393
394     private synchronized void createAdjRibOutListener(final TablesKey key,
395             final boolean mpSupport) {
396         final RIBSupport ribSupport = this.rib.getRibSupportContext().getRIBSupport(key);
397
398         // not particularly nice
399         if (ribSupport != null && this.session instanceof BGPSessionImpl) {
400             final ChannelOutputLimiter limiter = ((BGPSessionImpl) this.session).getLimiter();
401             final AdjRibOutListener adjRibOut = AdjRibOutListener.create(this.peerId, key,
402                     this.rib.getYangRibId(), this.rib.getCodecsRegistry(), ribSupport,
403                     this.rib.getService(), limiter, mpSupport);
404             this.adjRibOutListenerSet.put(key, adjRibOut);
405             registerPrefixesSentCounter(key, adjRibOut);
406         }
407     }
408
409     private synchronized ListenableFuture<Void> cleanup() {
410         // FIXME: BUG-196: support graceful
411         this.adjRibOutListenerSet.values().forEach(AdjRibOutListener::close);
412         this.adjRibOutListenerSet.clear();
413         if (this.effRibInWriter != null) {
414             this.effRibInWriter.close();
415         }
416         this.tables = Collections.emptySet();
417         this.addPathTableMaps = Collections.emptyMap();
418         if (this.ribWriter != null) {
419             return this.ribWriter.removePeer();
420         }
421         return Futures.immediateFuture(null);
422     }
423
424     @Override
425     public synchronized void onSessionDown(final BGPSession session, final Exception e) {
426         if (e.getMessage().equals(BGPSessionImpl.END_OF_INPUT)) {
427             LOG.info("Session with peer {} went down", this.name);
428         } else {
429             LOG.info("Session with peer {} went down", this.name, e);
430         }
431         releaseConnection();
432     }
433
434     @Override
435     public synchronized void onSessionTerminated(final BGPSession session, final BGPTerminationReason cause) {
436         LOG.info("Session with peer {} terminated: {}", this.name, cause);
437         releaseConnection();
438     }
439
440     @Override
441     public String toString() {
442         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
443     }
444
445     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
446         toStringHelper.add("name", this.name);
447         toStringHelper.add("tables", this.tables);
448         return toStringHelper;
449     }
450
451     @Override
452     public String getName() {
453         return this.name;
454     }
455
456     @Override
457     public synchronized ListenableFuture<Void> releaseConnection() {
458         if (this.rpcRegistration != null) {
459             this.rpcRegistration.close();
460         }
461         closeRegistration();
462         final ListenableFuture<Void> future = cleanup();
463
464         if (this.session != null) {
465             try {
466                 this.session.close();
467             } catch (final Exception e) {
468                 LOG.warn("Error closing session with peer", e);
469             }
470             this.session = null;
471         }
472         resetState();
473         return future;
474     }
475
476     private synchronized void closeRegistration() {
477         if (this.trackerRegistration != null) {
478             this.trackerRegistration.close();
479             this.trackerRegistration = null;
480         }
481     }
482
483     @Override
484     public synchronized byte[] getRawIdentifier() {
485         return Arrays.copyOf(this.rawIdentifier, this.rawIdentifier.length);
486     }
487
488     @Override
489     public PeerId getPeerId() {
490         return this.peerId;
491     }
492
493     @SuppressFBWarnings("IS2_INCONSISTENT_SYNC")
494     @Override
495     public SendReceive getSupportedAddPathTables(final TablesKey tableKey) {
496         return this.addPathTableMaps.get(tableKey);
497     }
498
499     @Override
500     public boolean supportsTable(final TablesKey tableKey) {
501         return this.tables.contains(tableKey);
502     }
503
504     @Override
505     public PeerRole getRole() {
506         return this.peerRole;
507     }
508
509     @Override
510     public ClusterIdentifier getClusterId() {
511         return this.clusterId;
512     }
513
514     @Override
515     public AsNumber getLocalAs() {
516         return this.localAs;
517     }
518
519     @Override
520     public AsNumber getFromPeerLocalAs() {
521         return getLocalAs();
522     }
523
524     @Override
525     public KeyedInstanceIdentifier<Tables, TablesKey> getRibOutIId(final TablesKey tablesKey) {
526         return this.tablesIId.getUnchecked(tablesKey);
527     }
528
529     @Override
530     public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
531             final AsyncTransaction<?, ?> transaction, final Throwable cause) {
532         LOG.error("Transaction chain failed.", cause);
533         this.chain.close();
534         //FIXME
535         /*
536         this.chain = this.rib.createPeerDOMChain(this);
537         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.chain);
538         releaseConnection();*/
539     }
540
541     @Override
542     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
543         LOG.debug("Transaction chain {} successful.", chain);
544     }
545
546     @Override
547     public synchronized void markUptodate(final TablesKey tablesKey) {
548         this.ribWriter.markTableUptodate(tablesKey);
549     }
550
551     @Override
552     public BGPErrorHandlingState getBGPErrorHandlingState() {
553         return this;
554     }
555
556     @Override
557     public BGPAfiSafiState getBGPAfiSafiState() {
558         return this;
559     }
560
561     @Override
562     public synchronized BGPSessionState getBGPSessionState() {
563         if (this.session instanceof BGPSessionStateProvider) {
564             return ((BGPSessionStateProvider) this.session).getBGPSessionState();
565         }
566         return null;
567     }
568
569     @Override
570     public synchronized BGPTimersState getBGPTimersState() {
571         if (this.session instanceof BGPSessionStateProvider) {
572             return ((BGPSessionStateProvider) this.session).getBGPTimersState();
573         }
574         return null;
575     }
576
577     @Override
578     public synchronized BGPTransportState getBGPTransportState() {
579         if (this.session instanceof BGPSessionStateProvider) {
580             return ((BGPSessionStateProvider) this.session).getBGPTransportState();
581         }
582         return null;
583     }
584
585     @Override
586     public PeerRole getFromPeerRole() {
587         return getRole();
588     }
589
590     @Override
591     public PeerId getFromPeerId() {
592         return getPeerId();
593     }
594
595     @Override
596     public ClusterIdentifier getFromClusterId() {
597         return getClusterId();
598     }
599 }