Fix Peer Identifier used per Rib creation.
[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.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     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             .rev171207.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.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         this.peerIId = getInstanceIdentifier().child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns
346                 .yang.bgp.rib.rev171207.bgp.rib.rib.Peer.class, new PeerKey(this.peerId));
347         this.peerRibOutIId = this.peerIId.child(AdjRibOut.class);
348         final Set<TablesKey> setTables = advertizedTableTypes.stream().map(t -> new TablesKey(t.getAfi(), t.getSafi()))
349                 .collect(Collectors.toSet());
350         this.tables = ImmutableSet.copyOf(setTables);
351
352         setAdvertizedGracefulRestartTableTypes(advertizedGracefulRestartTableTypes.stream()
353                 .map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toList()));
354         this.addPathTableMaps = ImmutableMap.copyOf(mapTableTypesFamilies(addPathTablesType));
355         this.trackerRegistration = this.rib.getPeerTracker().registerPeer(this);
356
357         for (final TablesKey key : this.tables) {
358             createAdjRibOutListener(key, true);
359         }
360
361         addBgp4Support();
362
363         this.effRibInWriter = EffectiveRibInWriter.create(this, this.rib, this.rib.createPeerChain(this),
364                 this.peerIId, this.tables);
365
366
367         registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter);
368         this.ribWriter = this.ribWriter.transform(this.peerId, this.rib.getRibSupportContext(), this.tables,
369                 this.addPathTableMaps);
370
371         if (this.rpcRegistry != null) {
372             this.rpcRegistration = this.rpcRegistry.addRoutedRpcImplementation(BgpPeerRpcService.class,
373                     new BgpPeerRpc(this, session, this.tables));
374             final KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib
375                     .rev171207.bgp.rib.rib.Peer, PeerKey> path = this.rib.getInstanceIdentifier()
376                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.bgp.rib
377                              .rib.Peer.class, new PeerKey(this.peerId));
378             this.rpcRegistration.registerPath(PeerContext.class, path);
379         }
380     }
381
382     //try to add a support for old-school BGP-4, if peer did not advertise IPv4-Unicast MP capability
383     private synchronized void addBgp4Support() {
384         final TablesKey key = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
385         if (!this.tables.contains(key)) {
386             final HashSet<TablesKey> newSet = new HashSet<>(this.tables);
387             newSet.add(key);
388             this.tables = ImmutableSet.copyOf(newSet);
389             createAdjRibOutListener(key, false);
390         }
391     }
392
393     private synchronized void createAdjRibOutListener(final TablesKey key,
394             final boolean mpSupport) {
395         final RIBSupport ribSupport = this.rib.getRibSupportContext().getRIBSupport(key);
396
397         // not particularly nice
398         if (ribSupport != null && this.session instanceof BGPSessionImpl) {
399             final ChannelOutputLimiter limiter = ((BGPSessionImpl) this.session).getLimiter();
400             final AdjRibOutListener adjRibOut = AdjRibOutListener.create(this.peerId, key,
401                     this.rib.getYangRibId(), this.rib.getCodecsRegistry(), ribSupport,
402                     this.rib.getService(), limiter, mpSupport);
403             this.adjRibOutListenerSet.put(key, adjRibOut);
404             registerPrefixesSentCounter(key, adjRibOut);
405         }
406     }
407
408     private synchronized ListenableFuture<Void> cleanup() {
409         // FIXME: BUG-196: support graceful
410         this.adjRibOutListenerSet.values().forEach(AdjRibOutListener::close);
411         this.adjRibOutListenerSet.clear();
412         if (this.effRibInWriter != null) {
413             this.effRibInWriter.close();
414         }
415         this.tables = Collections.emptySet();
416         this.addPathTableMaps = Collections.emptyMap();
417         if (this.ribWriter != null) {
418             return this.ribWriter.removePeer();
419         }
420         return Futures.immediateFuture(null);
421     }
422
423     @Override
424     public synchronized void onSessionDown(final BGPSession session, final Exception e) {
425         if (e.getMessage().equals(BGPSessionImpl.END_OF_INPUT)) {
426             LOG.info("Session with peer {} went down", this.name);
427         } else {
428             LOG.info("Session with peer {} went down", this.name, e);
429         }
430         releaseConnection();
431     }
432
433     @Override
434     public synchronized void onSessionTerminated(final BGPSession session, final BGPTerminationReason cause) {
435         LOG.info("Session with peer {} terminated: {}", this.name, cause);
436         releaseConnection();
437     }
438
439     @Override
440     public String toString() {
441         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
442     }
443
444     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
445         toStringHelper.add("name", this.name);
446         toStringHelper.add("tables", this.tables);
447         return toStringHelper;
448     }
449
450     @Override
451     public String getName() {
452         return this.name;
453     }
454
455     @Override
456     public synchronized ListenableFuture<Void> releaseConnection() {
457         if (this.rpcRegistration != null) {
458             this.rpcRegistration.close();
459         }
460         closeRegistration();
461         final ListenableFuture<Void> future = cleanup();
462
463         if (this.session != null) {
464             try {
465                 this.session.close();
466             } catch (final Exception e) {
467                 LOG.warn("Error closing session with peer", e);
468             }
469             this.session = null;
470         }
471         resetState();
472         return future;
473     }
474
475     private synchronized void closeRegistration() {
476         if (this.trackerRegistration != null) {
477             this.trackerRegistration.close();
478             this.trackerRegistration = null;
479         }
480     }
481
482     @Override
483     public synchronized byte[] getRawIdentifier() {
484         return Arrays.copyOf(this.rawIdentifier, this.rawIdentifier.length);
485     }
486
487     @Override
488     public PeerId getPeerId() {
489         return this.peerId;
490     }
491
492     @SuppressFBWarnings("IS2_INCONSISTENT_SYNC")
493     @Override
494     public SendReceive getSupportedAddPathTables(final TablesKey tableKey) {
495         return this.addPathTableMaps.get(tableKey);
496     }
497
498     @Override
499     public boolean supportsTable(final TablesKey tableKey) {
500         return this.tables.contains(tableKey);
501     }
502
503     @Override
504     public PeerRole getRole() {
505         return this.peerRole;
506     }
507
508     @Override
509     public ClusterIdentifier getClusterId() {
510         return this.clusterId;
511     }
512
513     @Override
514     public AsNumber getLocalAs() {
515         return this.localAs;
516     }
517
518     @Override
519     public AsNumber getFromPeerLocalAs() {
520         return getLocalAs();
521     }
522
523     @Override
524     public KeyedInstanceIdentifier<Tables, TablesKey> getRibOutIId(final TablesKey tablesKey) {
525         return this.tablesIId.getUnchecked(tablesKey);
526     }
527
528     @Override
529     public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
530             final AsyncTransaction<?, ?> transaction, final Throwable cause) {
531         LOG.error("Transaction chain failed.", cause);
532         this.chain.close();
533         //FIXME
534         /*
535         this.chain = this.rib.createPeerDOMChain(this);
536         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.chain);
537         releaseConnection();*/
538     }
539
540     @Override
541     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
542         LOG.debug("Transaction chain {} successful.", chain);
543     }
544
545     @Override
546     public synchronized void markUptodate(final TablesKey tablesKey) {
547         this.ribWriter.markTableUptodate(tablesKey);
548     }
549
550     @Override
551     public BGPErrorHandlingState getBGPErrorHandlingState() {
552         return this;
553     }
554
555     @Override
556     public BGPAfiSafiState getBGPAfiSafiState() {
557         return this;
558     }
559
560     @Override
561     public synchronized BGPSessionState getBGPSessionState() {
562         if (this.session instanceof BGPSessionStateProvider) {
563             return ((BGPSessionStateProvider) this.session).getBGPSessionState();
564         }
565         return null;
566     }
567
568     @Override
569     public synchronized BGPTimersState getBGPTimersState() {
570         if (this.session instanceof BGPSessionStateProvider) {
571             return ((BGPSessionStateProvider) this.session).getBGPTimersState();
572         }
573         return null;
574     }
575
576     @Override
577     public synchronized BGPTransportState getBGPTransportState() {
578         if (this.session instanceof BGPSessionStateProvider) {
579             return ((BGPSessionStateProvider) this.session).getBGPTransportState();
580         }
581         return null;
582     }
583
584     @Override
585     public PeerRole getFromPeerRole() {
586         return getRole();
587     }
588
589     @Override
590     public PeerId getFromPeerId() {
591         return getPeerId();
592     }
593
594     @Override
595     public ClusterIdentifier getFromClusterId() {
596         return getClusterId();
597     }
598 }