Fix findbug complains
[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     @GuardedBy("this")
120     private AbstractRegistration trackerRegistration;
121     private final LoadingCache<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>> tablesIId
122             = CacheBuilder.newBuilder()
123             .build(new CacheLoader<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>>() {
124                 @Override
125                 public KeyedInstanceIdentifier<Tables, TablesKey> load(final TablesKey tablesKey) {
126                     return BGPPeer.this.peerRibOutIId.child(Tables.class, tablesKey);
127                 }
128             });
129
130     @GuardedBy("this")
131     private BGPSession session;
132     @GuardedBy("this")
133     private byte[] rawIdentifier;
134     @GuardedBy("this")
135     private DOMTransactionChain chain;
136     @GuardedBy("this")
137     private AdjRibInWriter ribWriter;
138     @GuardedBy("this")
139     private EffectiveRibInWriter effRibInWriter;
140     private RoutedRpcRegistration<BgpPeerRpcService> rpcRegistration;
141     private Map<TablesKey, SendReceive> addPathTableMaps = Collections.emptyMap();
142     private PeerId peerId;
143
144     public BGPPeer(
145             final IpAddress neighborAddress,
146             final String peerGroupName,
147             final RIB rib,
148             final PeerRole role,
149             final ClusterIdentifier clusterId,
150             final AsNumber localAs,
151             final RpcProviderRegistry rpcRegistry,
152             final Set<TablesKey> afiSafisAdvertized,
153             final Set<TablesKey> afiSafisGracefulAdvertized) {
154         super(rib.getInstanceIdentifier(), peerGroupName, neighborAddress, afiSafisAdvertized,
155                 afiSafisGracefulAdvertized);
156         this.peerRole = role;
157         this.rib = requireNonNull(rib);
158         this.clusterId = clusterId;
159         this.localAs = localAs;
160         this.name = Ipv4Util.toStringIP(neighborAddress);
161         this.rpcRegistry = rpcRegistry;
162         this.chain = rib.createPeerDOMChain(this);
163     }
164
165     BGPPeer(
166             final IpAddress neighborAddress,
167             final RIB rib,
168             final PeerRole role,
169             final RpcProviderRegistry rpcRegistry,
170             final Set<TablesKey> afiSafisAdvertized,
171             final Set<TablesKey> afiSafisGracefulAdvertized) {
172         this(neighborAddress, null, rib, role, null, null, rpcRegistry, afiSafisAdvertized,
173                 afiSafisGracefulAdvertized);
174     }
175
176
177     private static Attributes nextHopToAttribute(final Attributes attrs, final MpReachNlri mpReach) {
178         if (attrs.getCNextHop() == null && mpReach.getCNextHop() != null) {
179             final AttributesBuilder attributesBuilder = new AttributesBuilder(attrs);
180             attributesBuilder.setCNextHop(mpReach.getCNextHop());
181             return attributesBuilder.build();
182         }
183         return attrs;
184     }
185
186     /**
187      * Creates MPReach for the prefixes to be handled in the same way as linkstate routes.
188      *
189      * @param message Update message containing prefixes in NLRI
190      * @return MpReachNlri with prefixes from the nlri field
191      */
192     private static MpReachNlri prefixesToMpReach(final Update message) {
193         final List<Ipv4Prefixes> prefixes = message.getNlri().stream()
194                 .map(n -> new Ipv4PrefixesBuilder().setPrefix(n.getPrefix()).setPathId(n.getPathId()).build())
195                 .collect(Collectors.toList());
196         final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
197                 UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
198                 new AdvertizedRoutesBuilder().setDestinationType(
199                         new DestinationIpv4CaseBuilder().setDestinationIpv4(
200                                 new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
201         if (message.getAttributes() != null) {
202             b.setCNextHop(message.getAttributes().getCNextHop());
203         }
204         return b.build();
205     }
206
207     /**
208      * Create MPUnreach for the prefixes to be handled in the same way as linkstate routes.
209      *
210      * @param message            Update message containing withdrawn routes
211      * @param isAnyNlriAnnounced isAnyNlriAnnounced
212      * @return MpUnreachNlri with prefixes from the withdrawn routes field
213      */
214     private static MpUnreachNlri prefixesToMpUnreach(final Update message, final boolean isAnyNlriAnnounced) {
215         final List<Ipv4Prefixes> prefixes = new ArrayList<>();
216         message.getWithdrawnRoutes().forEach(w -> {
217
218             Optional<Nlri> nlriAnounced = Optional.empty();
219             if (isAnyNlriAnnounced) {
220                 nlriAnounced = message.getNlri().stream().filter(n -> Objects.equal(n.getPrefix(), w.getPrefix())
221                         && Objects.equal(n.getPathId(), w.getPathId()))
222                         .findAny();
223             }
224             if (!nlriAnounced.isPresent()) {
225                 prefixes.add(new Ipv4PrefixesBuilder().setPrefix(w.getPrefix()).setPathId(w.getPathId()).build());
226             }
227         });
228         return new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class)
229                 .setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(new org.opendaylight.yang.gen.v1
230                         .urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update.attributes.mp.unreach.nlri
231                         .withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
232                         new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build();
233     }
234
235     private static Map<TablesKey, SendReceive> mapTableTypesFamilies(final List<AddressFamilies> addPathTablesType) {
236         return ImmutableMap.copyOf(addPathTablesType.stream().collect(Collectors.toMap(af -> new TablesKey(af.getAfi(),
237                         af.getSafi()), BgpAddPathTableType::getSendReceive)));
238     }
239
240     public synchronized void instantiateServiceInstance() {
241         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.chain);
242         setActive(true);
243     }
244
245     // FIXME ListenableFuture<?> should be used once closeServiceInstance uses wildcard too
246     @Override
247     public synchronized ListenableFuture<Void> close() {
248         final ListenableFuture<Void> future = releaseConnection();
249         this.chain.close();
250         setActive(false);
251         return future;
252     }
253
254     @Override
255     public void onMessage(final BGPSession session, final Notification msg) throws BGPDocumentedException {
256         if (!(msg instanceof Update) && !(msg instanceof RouteRefresh)) {
257             LOG.info("Ignoring unhandled message class {}", msg.getClass());
258             return;
259         }
260         if (msg instanceof Update) {
261             onUpdateMessage((Update) msg);
262         } else {
263             onRouteRefreshMessage((RouteRefresh) msg);
264         }
265     }
266
267     private void onRouteRefreshMessage(final RouteRefresh message) {
268         final Class<? extends AddressFamily> rrAfi = message.getAfi();
269         final Class<? extends SubsequentAddressFamily> rrSafi = message.getSafi();
270
271         final TablesKey key = new TablesKey(rrAfi, rrSafi);
272         final AdjRibOutListener listener = this.adjRibOutListenerSet.get(key);
273         if (listener != null) {
274             listener.close();
275             this.adjRibOutListenerSet.remove(key);
276             createAdjRibOutListener(key, listener.isMpSupported());
277         } else {
278             LOG.info("Ignoring RouteRefresh message. Afi/Safi is not supported: {}, {}.", rrAfi, rrSafi);
279         }
280     }
281
282     /**
283      * Check for presence of well known mandatory attribute LOCAL_PREF in Update message.
284      *
285      * @param message Update message
286      */
287     private void checkMandatoryAttributesPresence(final Update message) throws BGPDocumentedException {
288         if (MessageUtil.isAnyNlriPresent(message)) {
289             final Attributes attrs = message.getAttributes();
290             if (this.peerRole == PeerRole.Ibgp && (attrs == null || attrs.getLocalPref() == null)) {
291                 throw new BGPDocumentedException(BGPError.MANDATORY_ATTR_MISSING_MSG + "LOCAL_PREF",
292                         BGPError.WELL_KNOWN_ATTR_MISSING,
293                         new byte[]{LocalPreferenceAttributeParser.TYPE});
294             }
295         }
296     }
297
298     /**
299      * Process Update message received.
300      * Calls {@link #checkMandatoryAttributesPresence(Update)} to check for presence of mandatory attributes.
301      *
302      * @param message Update message
303      */
304     private synchronized void onUpdateMessage(final Update message) throws BGPDocumentedException {
305         checkMandatoryAttributesPresence(message);
306
307         // update AdjRibs
308         final Attributes attrs = message.getAttributes();
309         MpReachNlri mpReach;
310         final boolean isAnyNlriAnnounced = message.getNlri() != null;
311         if (isAnyNlriAnnounced) {
312             mpReach = prefixesToMpReach(message);
313         } else {
314             mpReach = MessageUtil.getMpReachNlri(attrs);
315         }
316         if (mpReach != null) {
317             this.ribWriter.updateRoutes(mpReach, nextHopToAttribute(attrs, mpReach));
318         }
319         MpUnreachNlri mpUnreach;
320         if (message.getWithdrawnRoutes() != null) {
321             mpUnreach = prefixesToMpUnreach(message, isAnyNlriAnnounced);
322         } else {
323             mpUnreach = MessageUtil.getMpUnreachNlri(attrs);
324         }
325         if (mpUnreach != null) {
326             this.ribWriter.removeRoutes(mpUnreach);
327         }
328     }
329
330     @Override
331     public synchronized void onSessionUp(final BGPSession session) {
332         this.session = session;
333         if (this.session instanceof BGPSessionStateProvider) {
334             ((BGPSessionStateProvider) this.session).registerMessagesCounter(this);
335         }
336
337         final List<AddressFamilies> addPathTablesType = session.getAdvertisedAddPathTableTypes();
338         final Set<BgpTableType> advertizedTableTypes = session.getAdvertisedTableTypes();
339         final List<BgpTableType> advertizedGracefulRestartTableTypes = session.getAdvertisedGracefulRestartTableTypes();
340         LOG.info("Session with peer {} went up with tables {} and Add Path tables {}", this.name,
341                 advertizedTableTypes, addPathTablesType);
342         this.rawIdentifier = InetAddresses.forString(session.getBgpId().getValue()).getAddress();
343         this.peerId = RouterIds.createPeerId(session.getBgpId());
344         final KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib
345                 .rev180329.bgp.rib.rib.Peer, PeerKey> peerIId =
346                 getInstanceIdentifier().child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns
347                 .yang.bgp.rib.rev180329.bgp.rib.rib.Peer.class, new PeerKey(this.peerId));
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         this.effRibInWriter = new EffectiveRibInWriter(this, this.rib, this.rib.createPeerChain(this),
352                 peerIId, this.tables);
353         registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter);
354         this.peerRibOutIId = peerIId.child(AdjRibOut.class);
355         this.effRibInWriter.init();
356         setAdvertizedGracefulRestartTableTypes(advertizedGracefulRestartTableTypes.stream()
357                 .map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toList()));
358         this.addPathTableMaps = ImmutableMap.copyOf(mapTableTypesFamilies(addPathTablesType));
359         this.trackerRegistration = this.rib.getPeerTracker().registerPeer(this);
360
361         for (final TablesKey key : this.tables) {
362             createAdjRibOutListener(key, true);
363         }
364
365         addBgp4Support();
366
367         this.ribWriter = this.ribWriter.transform(this.peerId, this.rib.getRibSupportContext(), this.tables,
368                 this.addPathTableMaps);
369
370         if (this.rpcRegistry != null) {
371             this.rpcRegistration = this.rpcRegistry.addRoutedRpcImplementation(BgpPeerRpcService.class,
372                     new BgpPeerRpc(this, session, this.tables));
373             final KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib
374                     .rev180329.bgp.rib.rib.Peer, PeerKey> path = this.rib.getInstanceIdentifier()
375                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib
376                              .rib.Peer.class, new PeerKey(this.peerId));
377             this.rpcRegistration.registerPath(PeerContext.class, path);
378         }
379     }
380
381     //try to add a support for old-school BGP-4, if peer did not advertise IPv4-Unicast MP capability
382     private synchronized void addBgp4Support() {
383         final TablesKey key = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
384         if (!this.tables.contains(key)) {
385             final HashSet<TablesKey> newSet = new HashSet<>(this.tables);
386             newSet.add(key);
387             this.tables = ImmutableSet.copyOf(newSet);
388             createAdjRibOutListener(key, false);
389         }
390     }
391
392     private synchronized void createAdjRibOutListener(final TablesKey key,
393             final boolean mpSupport) {
394         final RIBSupport ribSupport = this.rib.getRibSupportContext().getRIBSupport(key);
395
396         // not particularly nice
397         if (ribSupport != null && this.session instanceof BGPSessionImpl) {
398             final ChannelOutputLimiter limiter = ((BGPSessionImpl) this.session).getLimiter();
399             final AdjRibOutListener adjRibOut = AdjRibOutListener.create(this.peerId, key,
400                     this.rib.getYangRibId(), this.rib.getCodecsRegistry(), ribSupport,
401                     this.rib.getService(), limiter, mpSupport);
402             this.adjRibOutListenerSet.put(key, adjRibOut);
403             registerPrefixesSentCounter(key, adjRibOut);
404         }
405     }
406
407     @SuppressFBWarnings(value = "NP_NONNULL_PARAM_VIOLATION", justification = "Unrecognised NullableDecl")
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 }