BUG-2383 : wire AdjRibOutListener to BGPPeer
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / RIBImpl.java
1 /*
2  * Copyright (c) 2013 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 com.google.common.base.MoreObjects;
11 import com.google.common.base.MoreObjects.ToStringHelper;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableSet;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Set;
22 import java.util.concurrent.BlockingQueue;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.concurrent.ConcurrentMap;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.LinkedBlockingQueue;
27 import javax.annotation.concurrent.ThreadSafe;
28 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
34 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
35 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
39 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
40 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
41 import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOut;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOutRegistration;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
46 import org.opendaylight.protocol.bgp.rib.spi.AbstractAdjRIBs;
47 import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
48 import org.opendaylight.protocol.bgp.rib.spi.BGPObjectComparator;
49 import org.opendaylight.protocol.bgp.rib.spi.Peer;
50 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
51 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.DestinationIpv4Builder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationIpv4CaseBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.Nlri;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.WithdrawnRoutes;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlri;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRibBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
88 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
89 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
90 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
91 import org.opendaylight.yangtools.yang.common.QName;
92 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
93 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
94 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
95 import org.slf4j.Logger;
96 import org.slf4j.LoggerFactory;
97
98 @ThreadSafe
99 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
100     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
101     private static final Update EOR = new UpdateBuilder().build();
102     private static final TablesKey IPV4_UNICAST_TABLE = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
103     private static final QName RIB_ID_QNAME = QName.cachedReference(QName.create(Rib.QNAME, "id"));
104
105     /*
106      * FIXME: performance: this needs to be turned into a Peer->offset map.
107      *        The offset is used to locate a the per-peer state entry in the
108      *        RIB tables.
109      *
110      *        For the first release, that map is updated whenever configuration
111      *        changes and remains constant on peer flaps. On re-configuration
112      *        a resize task is scheduled, so large tables may take some time
113      *        before they continue reacting to updates.
114      *
115      *        For subsequent releases, if we make the reformat process concurrent,
116      *        we can trigger reformats when Graceful Restart Time expires for a
117      *        particular peer.
118      */
119     private final ConcurrentMap<Peer, AdjRIBsOut> ribOuts = new ConcurrentHashMap<>();
120     private final ReconnectStrategyFactory tcpStrategyFactory;
121     private final ReconnectStrategyFactory sessionStrategyFactory;
122
123     /**
124      * BGP Best Path selection comparator for ingress best path selection.
125      */
126     private final BGPObjectComparator comparator;
127     private final BGPDispatcher dispatcher;
128     private final BindingTransactionChain chain;
129     private final AsNumber localAs;
130     private final Ipv4Address bgpIdentifier;
131     private final ClusterIdentifier clusterId;
132     private final Set<BgpTableType> localTables;
133     private final Set<TablesKey> localTablesKeys;
134     private final RIBTables tables;
135     private final BlockingQueue<Peer> peers;
136     private final DataBroker dataBroker;
137     private final DOMDataBroker domDataBroker;
138     private final RIBExtensionConsumerContext extensions;
139     private final YangInstanceIdentifier yangRibId;
140     private final RIBSupportContextRegistryImpl ribContextRegistry;
141     private final EffectiveRibInWriter efWriter;
142     private final DOMDataBrokerExtension service;
143
144     private final Runnable scheduler = new Runnable() {
145         @Override
146         public void run() {
147             try {
148                 final Peer peer = RIBImpl.this.peers.take();
149                 LOG.debug("Advertizing loc-rib to new peer {}.", peer);
150                 for (final BgpTableType key : RIBImpl.this.localTables) {
151
152                     synchronized (RIBImpl.this) {
153                         final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(RIBImpl.this.ribOuts, RIBImpl.this.comparator, RIBImpl.this.chain.newWriteOnlyTransaction());
154                         final AbstractAdjRIBs<?, ?, ?> adj = (AbstractAdjRIBs<?, ?, ?>) RIBImpl.this.tables.get(new TablesKey(key.getAfi(), key.getSafi()));
155                         adj.addAllEntries(trans);
156                         Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
157                             @Override
158                             public void onSuccess(final Void result) {
159                                 LOG.trace("Advertizing {} to peer {} committed successfully", key.getAfi(), peer);
160                             }
161                             @Override
162                             public void onFailure(final Throwable t) {
163                                 LOG.error("Failed to update peer {} with RIB {}", peer, t);
164                             }
165                         });
166                     }
167                 }
168             } catch (final InterruptedException e) {
169                 LOG.info("Scheduler thread was interrupted.", e);
170             }
171         }
172     };
173
174     public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
175         final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
176         final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final GeneratedClassLoadingStrategy classStrategy) {
177         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
178         this.chain = dps.createTransactionChain(this);
179         this.localAs = Preconditions.checkNotNull(localAs);
180         this.comparator = new BGPObjectComparator(localAs);
181         this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
182         this.clusterId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
183         this.dispatcher = Preconditions.checkNotNull(dispatcher);
184         this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
185         this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
186         this.localTables = ImmutableSet.copyOf(localTables);
187         this.localTablesKeys = new HashSet<TablesKey>();
188         this.tables = new RIBTables(extensions);
189         this.peers = new LinkedBlockingQueue<>();
190         this.dataBroker = dps;
191         this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
192         this.extensions = Preconditions.checkNotNull(extensions);
193         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecFactory, classStrategy);
194         this.yangRibId = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME).nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
195
196         LOG.debug("Instantiating RIB table {} at {}", ribId, getInstanceIdentifier());
197
198         final WriteTransaction trans = this.chain.newWriteOnlyTransaction();
199
200         // put empty BgpRib if not exists
201         trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier(),
202             new RibBuilder().setKey(new RibKey(ribId)).setPeer(Collections.<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer> emptyList()).setId(ribId).setLocRib(
203             new LocRibBuilder().setTables(Collections.<Tables> emptyList()).build()).build(), true);
204
205         for (final BgpTableType t : localTables) {
206             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
207             this.localTablesKeys.add(key);
208             if (this.tables.create(trans, this, key) == null) {
209                 LOG.debug("Did not create local table for unhandled table type {}", t);
210             }
211         }
212
213         Futures.addCallback(trans.submit(), new FutureCallback<Void>() {
214             @Override
215             public void onSuccess(final Void result) {
216                 LOG.trace("Change committed successfully");
217             }
218
219             @Override
220             public void onFailure(final Throwable t) {
221                 LOG.error("Failed to initiate RIB {}", getInstanceIdentifier(), t);
222             }
223
224         });
225
226         final PolicyDatabase pd  = new PolicyDatabase(localAs.getValue(), localBgpId, this.clusterId);
227
228         final DOMDataBrokerExtension service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
229         this.service = service;
230         this.efWriter = EffectiveRibInWriter.create(getService(), this.createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
231         LOG.debug("Effective RIB created.");
232
233         for (final BgpTableType t : localTables) {
234             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
235             // create locRibWriter for each table
236             LocRibWriter.create(this.ribContextRegistry, key, this.createPeerChain(this), getYangRibId(), localAs, getService(), pd);
237         }
238     }
239
240     @Deprecated
241     synchronized void initTables(final byte[] remoteBgpId) {
242     }
243
244     @Override
245     @Deprecated
246     public synchronized void updateTables(final Peer peer, final Update message) {
247         final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(this.ribOuts, this.comparator, this.chain.newWriteOnlyTransaction());
248
249         if (!EOR.equals(message)) {
250             final WithdrawnRoutes wr = message.getWithdrawnRoutes();
251             if (wr != null) {
252                 final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
253                 if (ari != null) {
254                     /*
255                      * create MPUnreach for the routes to be handled in the same way as linkstate routes
256                      */
257                     final List<Ipv4Prefixes> prefixes = new ArrayList<>();
258                     for (final Ipv4Prefix p : wr.getWithdrawnRoutes()) {
259                         prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build());
260                     }
261                     ari.removeRoutes(
262                         trans,
263                         peer,
264                         new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).setWithdrawnRoutes(
265                             new WithdrawnRoutesBuilder().setDestinationType(
266                                 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
267                                     new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build());
268                 } else {
269                     LOG.debug("Not removing objects from unhandled IPv4 Unicast");
270                 }
271             }
272
273             final Attributes attrs = message.getAttributes();
274             if (attrs != null) {
275                 final Attributes2 mpu = attrs.getAugmentation(Attributes2.class);
276                 if (mpu != null) {
277                     final MpUnreachNlri nlri = mpu.getMpUnreachNlri();
278                     final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
279                     // EOR messages do not contain withdrawn routes
280                     if (nlri.getWithdrawnRoutes() != null) {
281                         if (ari != null) {
282                             ari.removeRoutes(trans, peer, nlri);
283                         } else {
284                             LOG.debug("Not removing objects from unhandled NLRI {}", nlri);
285                         }
286                     } else {
287                         ari.markUptodate(trans, peer);
288                     }
289                 }
290             }
291
292             final Nlri ar = message.getNlri();
293             if (ar != null) {
294                 final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
295                 if (ari != null) {
296                     /*
297                      * create MPReach for the routes to be handled in the same way as linkstate routes
298                      */
299                     final List<Ipv4Prefixes> prefixes = new ArrayList<>();
300                     for (final Ipv4Prefix p : ar.getNlri()) {
301                         prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build());
302                     }
303                     final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
304                         UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
305                             new AdvertizedRoutesBuilder().setDestinationType(
306                                 new DestinationIpv4CaseBuilder().setDestinationIpv4(
307                                     new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
308                     if (attrs != null) {
309                         b.setCNextHop(attrs.getCNextHop());
310                     }
311
312                     ari.addRoutes(trans, peer, b.build(), attrs);
313                 } else {
314                     LOG.debug("Not adding objects from unhandled IPv4 Unicast");
315                 }
316             }
317
318             if (attrs != null) {
319                 final Attributes1 mpr = attrs.getAugmentation(Attributes1.class);
320                 if (mpr != null) {
321                     final MpReachNlri nlri = mpr.getMpReachNlri();
322
323                     final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
324                     if (ari != null) {
325                         if (message.equals(ari.endOfRib())) {
326                             ari.markUptodate(trans, peer);
327                         } else {
328                             ari.addRoutes(trans, peer, nlri, attrs);
329                         }
330                     } else {
331                         LOG.debug("Not adding objects from unhandled NLRI {}", nlri);
332                     }
333                 }
334             }
335         } else {
336             final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
337             if (ari != null) {
338                 ari.markUptodate(trans, peer);
339             } else {
340                 LOG.debug("End-of-RIB for IPv4 Unicast ignored");
341             }
342         }
343
344         Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
345             @Override
346             public void onSuccess(final Void result) {
347                 LOG.debug("RIB modification successfully committed.");
348             }
349
350             @Override
351             public void onFailure(final Throwable t) {
352                 LOG.error("Failed to commit RIB modification", t);
353             }
354         });
355     }
356
357     @Deprecated
358     @Override
359     public synchronized void clearTable(final Peer peer, final TablesKey key) {
360         final AdjRIBsIn<?, ?> ari = this.tables.get(key);
361         if (ari != null) {
362             final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(this.ribOuts, this.comparator, this.chain.newWriteOnlyTransaction());
363             ari.clear(trans, peer);
364
365             Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
366                 @Override
367                 public void onSuccess(final Void result) {
368                     LOG.trace("Table {} cleared successfully", key);
369                 }
370
371                 @Override
372                 public void onFailure(final Throwable t) {
373                     LOG.error("Failed to clear table {}", key, t);
374                 }
375             });
376         }
377     }
378
379     @Override
380     public String toString() {
381         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
382     }
383
384     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
385         return toStringHelper;
386     }
387
388     @SuppressWarnings("unchecked")
389     @Deprecated
390     protected <K, V extends Route> AdjRIBsIn<K, V> getTable(final TablesKey key) {
391         return (AdjRIBsIn<K, V>) this.tables.get(key);
392     }
393
394     @Override
395     public synchronized void close() throws InterruptedException, ExecutionException {
396         final WriteTransaction t = this.chain.newWriteOnlyTransaction();
397         t.delete(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier());
398         t.submit().get();
399         this.chain.close();
400     }
401
402     @Override
403     public AsNumber getLocalAs() {
404         return this.localAs;
405     }
406
407     @Override
408     public Ipv4Address getBgpIdentifier() {
409         return this.bgpIdentifier;
410     }
411
412     @Override
413     public Set<? extends BgpTableType> getLocalTables() {
414         return this.localTables;
415     }
416
417     @Override
418     public ReconnectStrategyFactory getTcpStrategyFactory() {
419         return this.tcpStrategyFactory;
420     }
421
422     @Override
423     public ReconnectStrategyFactory getSessionStrategyFactory() {
424         return this.sessionStrategyFactory;
425     }
426
427     @Override
428     public BGPDispatcher getDispatcher() {
429         return this.dispatcher;
430     }
431
432     @Deprecated
433     @Override
434     public void initTable(final Peer bgpPeer, final TablesKey key) {
435         // FIXME: BUG-196: support graceful restart
436     }
437
438     @Override
439     public AdjRIBsOutRegistration registerRIBsOut(final Peer peer, final AdjRIBsOut aro) {
440         final AdjRIBsOutRegistration reg = new AdjRIBsOutRegistration(aro) {
441             @Override
442             protected void removeRegistration() {
443                 RIBImpl.this.ribOuts.remove(peer, aro);
444             }
445         };
446
447         this.ribOuts.put(peer, aro);
448         LOG.debug("Registering this peer {} to RIB-Out {}", peer, this.ribOuts);
449         try {
450             this.peers.put(peer);
451             new Thread(this.scheduler).start();
452         } catch (final InterruptedException e) {
453             //
454         }
455         return reg;
456     }
457
458     @Override
459     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
460         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause);
461     }
462
463     @Override
464     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
465         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
466     }
467
468     @Override
469     public long getRoutesCount(final TablesKey key) {
470         try {
471             final Optional<Tables> tableMaybe = this.dataBroker.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL,
472                     getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
473             if (tableMaybe.isPresent()) {
474                 final Tables table = tableMaybe.get();
475                 if (table.getRoutes() instanceof Ipv4RoutesCase) {
476                     final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) table.getRoutes();
477                     if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
478                         return routesCase.getIpv4Routes().getIpv4Route().size();
479                     }
480                 } else if (table.getRoutes() instanceof Ipv6RoutesCase) {
481                     final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) table.getRoutes();
482                     if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
483                         return routesCase.getIpv6Routes().getIpv6Route().size();
484                     }
485                 }
486             }
487         } catch (final ReadFailedException e) {
488             //no-op
489         }
490         return 0;
491     }
492
493     public Set<TablesKey> getLocalTablesKeys() {
494         return this.localTablesKeys;
495     }
496
497     public DOMDataTreeChangeService getService() {
498         return (DOMDataTreeChangeService) this.service;
499     }
500
501     @Override
502     public YangInstanceIdentifier getYangRibId() {
503         return this.yangRibId;
504     }
505
506     @Override
507     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
508         return this.domDataBroker.createTransactionChain(listener);
509     }
510
511     @Override
512     public RIBExtensionConsumerContext getRibExtensions() {
513         return this.extensions;
514     }
515
516     @Override
517     public RIBSupportContextRegistry getRibSupportContext() {
518         return this.ribContextRegistry;
519     }
520
521     @Override
522     public void onGlobalContextUpdated(final SchemaContext context) {
523         this.ribContextRegistry.onSchemaContextUpdated(context);
524     }
525 }