BGPCEP-577: Neighbor’s local AS configurable
[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 final InstanceIdentifier<AdjRibOut> peerRibOutIId;
119     private final 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.peerIId = getInstanceIdentifier().child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns
165                 .yang.bgp.rib.rev171207.bgp.rib.rib.Peer.class, new PeerKey(RouterIds.createPeerId(neighborAddress)));
166         this.peerRibOutIId = this.peerIId.child(AdjRibOut.class);
167         this.chain = rib.createPeerDOMChain(this);
168     }
169
170     BGPPeer(
171             final IpAddress neighborAddress,
172             final RIB rib,
173             final PeerRole role,
174             final RpcProviderRegistry rpcRegistry,
175             final Set<TablesKey> afiSafisAdvertized,
176             final Set<TablesKey> afiSafisGracefulAdvertized) {
177         this(neighborAddress, null, rib, role, null, null, rpcRegistry, afiSafisAdvertized,
178                 afiSafisGracefulAdvertized);
179     }
180
181
182     private static Attributes nextHopToAttribute(final Attributes attrs, final MpReachNlri mpReach) {
183         if (attrs.getCNextHop() == null && mpReach.getCNextHop() != null) {
184             final AttributesBuilder attributesBuilder = new AttributesBuilder(attrs);
185             attributesBuilder.setCNextHop(mpReach.getCNextHop());
186             return attributesBuilder.build();
187         }
188         return attrs;
189     }
190
191     /**
192      * Creates MPReach for the prefixes to be handled in the same way as linkstate routes.
193      *
194      * @param message Update message containing prefixes in NLRI
195      * @return MpReachNlri with prefixes from the nlri field
196      */
197     private static MpReachNlri prefixesToMpReach(final Update message) {
198         final List<Ipv4Prefixes> prefixes = message.getNlri().stream()
199                 .map(n -> new Ipv4PrefixesBuilder().setPrefix(n.getPrefix()).setPathId(n.getPathId()).build())
200                 .collect(Collectors.toList());
201         final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
202                 UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
203                 new AdvertizedRoutesBuilder().setDestinationType(
204                         new DestinationIpv4CaseBuilder().setDestinationIpv4(
205                                 new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
206         if (message.getAttributes() != null) {
207             b.setCNextHop(message.getAttributes().getCNextHop());
208         }
209         return b.build();
210     }
211
212     /**
213      * Create MPUnreach for the prefixes to be handled in the same way as linkstate routes.
214      *
215      * @param message            Update message containing withdrawn routes
216      * @param isAnyNlriAnnounced isAnyNlriAnnounced
217      * @return MpUnreachNlri with prefixes from the withdrawn routes field
218      */
219     private static MpUnreachNlri prefixesToMpUnreach(final Update message, final boolean isAnyNlriAnnounced) {
220         final List<Ipv4Prefixes> prefixes = new ArrayList<>();
221         message.getWithdrawnRoutes().forEach(w -> {
222
223             Optional<Nlri> nlriAnounced = Optional.empty();
224             if (isAnyNlriAnnounced) {
225                 nlriAnounced = message.getNlri().stream().filter(n -> Objects.equal(n.getPrefix(), w.getPrefix())
226                         && Objects.equal(n.getPathId(), w.getPathId()))
227                         .findAny();
228             }
229             if (!nlriAnounced.isPresent()) {
230                 prefixes.add(new Ipv4PrefixesBuilder().setPrefix(w.getPrefix()).setPathId(w.getPathId()).build());
231             }
232         });
233         return new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class)
234                 .setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(new org.opendaylight.yang.gen.v1
235                         .urn.opendaylight.params.xml.ns.yang.bgp.inet.rev171207.update.attributes.mp.unreach.nlri
236                         .withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
237                         new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build();
238     }
239
240     private static Map<TablesKey, SendReceive> mapTableTypesFamilies(final List<AddressFamilies> addPathTablesType) {
241         return ImmutableMap.copyOf(addPathTablesType.stream().collect(Collectors.toMap(af -> new TablesKey(af.getAfi(),
242                         af.getSafi()), BgpAddPathTableType::getSendReceive)));
243     }
244
245     public synchronized void instantiateServiceInstance() {
246         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.chain);
247         setActive(true);
248     }
249
250     // FIXME ListenableFuture<?> should be used once closeServiceInstance uses wildcard too
251     @Override
252     public synchronized ListenableFuture<Void> close() {
253         final ListenableFuture<Void> future = releaseConnection();
254         this.chain.close();
255         setActive(false);
256         return future;
257     }
258
259     @Override
260     public void onMessage(final BGPSession session, final Notification msg) throws BGPDocumentedException {
261         if (!(msg instanceof Update) && !(msg instanceof RouteRefresh)) {
262             LOG.info("Ignoring unhandled message class {}", msg.getClass());
263             return;
264         }
265         if (msg instanceof Update) {
266             onUpdateMessage((Update) msg);
267         } else {
268             onRouteRefreshMessage((RouteRefresh) msg);
269         }
270     }
271
272     private void onRouteRefreshMessage(final RouteRefresh message) {
273         final Class<? extends AddressFamily> rrAfi = message.getAfi();
274         final Class<? extends SubsequentAddressFamily> rrSafi = message.getSafi();
275
276         final TablesKey key = new TablesKey(rrAfi, rrSafi);
277         final AdjRibOutListener listener = this.adjRibOutListenerSet.get(key);
278         if (listener != null) {
279             listener.close();
280             this.adjRibOutListenerSet.remove(key);
281             createAdjRibOutListener(key, listener.isMpSupported());
282         } else {
283             LOG.info("Ignoring RouteRefresh message. Afi/Safi is not supported: {}, {}.", rrAfi, rrSafi);
284         }
285     }
286
287     /**
288      * Check for presence of well known mandatory attribute LOCAL_PREF in Update message.
289      *
290      * @param message Update message
291      */
292     private void checkMandatoryAttributesPresence(final Update message) throws BGPDocumentedException {
293         if (MessageUtil.isAnyNlriPresent(message)) {
294             final Attributes attrs = message.getAttributes();
295             if (this.peerRole == PeerRole.Ibgp && (attrs == null || attrs.getLocalPref() == null)) {
296                 throw new BGPDocumentedException(BGPError.MANDATORY_ATTR_MISSING_MSG + "LOCAL_PREF",
297                         BGPError.WELL_KNOWN_ATTR_MISSING,
298                         new byte[]{LocalPreferenceAttributeParser.TYPE});
299             }
300         }
301     }
302
303     /**
304      * Process Update message received.
305      * Calls {@link #checkMandatoryAttributesPresence(Update)} to check for presence of mandatory attributes.
306      *
307      * @param message Update message
308      */
309     private synchronized void onUpdateMessage(final Update message) throws BGPDocumentedException {
310         checkMandatoryAttributesPresence(message);
311
312         // update AdjRibs
313         final Attributes attrs = message.getAttributes();
314         MpReachNlri mpReach;
315         final boolean isAnyNlriAnnounced = message.getNlri() != null;
316         if (isAnyNlriAnnounced) {
317             mpReach = prefixesToMpReach(message);
318         } else {
319             mpReach = MessageUtil.getMpReachNlri(attrs);
320         }
321         if (mpReach != null) {
322             this.ribWriter.updateRoutes(mpReach, nextHopToAttribute(attrs, mpReach));
323         }
324         MpUnreachNlri mpUnreach;
325         if (message.getWithdrawnRoutes() != null) {
326             mpUnreach = prefixesToMpUnreach(message, isAnyNlriAnnounced);
327         } else {
328             mpUnreach = MessageUtil.getMpUnreachNlri(attrs);
329         }
330         if (mpUnreach != null) {
331             this.ribWriter.removeRoutes(mpUnreach);
332         }
333     }
334
335     @Override
336     public synchronized void onSessionUp(final BGPSession session) {
337         this.session = session;
338         if (this.session instanceof BGPSessionStateProvider) {
339             ((BGPSessionStateProvider) this.session).registerMessagesCounter(this);
340         }
341         final List<AddressFamilies> addPathTablesType = session.getAdvertisedAddPathTableTypes();
342         final Set<BgpTableType> advertizedTableTypes = session.getAdvertisedTableTypes();
343         final List<BgpTableType> advertizedGracefulRestartTableTypes = session.getAdvertisedGracefulRestartTableTypes();
344         LOG.info("Session with peer {} went up with tables {} and Add Path tables {}", this.name,
345                 advertizedTableTypes, addPathTablesType);
346         this.rawIdentifier = InetAddresses.forString(session.getBgpId().getValue()).getAddress();
347         this.peerId = RouterIds.createPeerId(session.getBgpId());
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 }