BUG-2383 : Application peer rework.
[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
143     private final Runnable scheduler = new Runnable() {
144         @Override
145         public void run() {
146             try {
147                 final Peer peer = RIBImpl.this.peers.take();
148                 LOG.debug("Advertizing loc-rib to new peer {}.", peer);
149                 for (final BgpTableType key : RIBImpl.this.localTables) {
150
151                     synchronized (RIBImpl.this) {
152                         final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(RIBImpl.this.ribOuts, RIBImpl.this.comparator, RIBImpl.this.chain.newWriteOnlyTransaction());
153                         final AbstractAdjRIBs<?, ?, ?> adj = (AbstractAdjRIBs<?, ?, ?>) RIBImpl.this.tables.get(new TablesKey(key.getAfi(), key.getSafi()));
154                         adj.addAllEntries(trans);
155                         Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
156                             @Override
157                             public void onSuccess(final Void result) {
158                                 LOG.trace("Advertizing {} to peer {} committed successfully", key.getAfi(), peer);
159                             }
160                             @Override
161                             public void onFailure(final Throwable t) {
162                                 LOG.error("Failed to update peer {} with RIB {}", peer, t);
163                             }
164                         });
165                     }
166                 }
167             } catch (final InterruptedException e) {
168                 LOG.info("Scheduler thread was interrupted.", e);
169             }
170         }
171     };
172
173     public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
174         final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
175         final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final GeneratedClassLoadingStrategy classStrategy) {
176         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
177         this.chain = dps.createTransactionChain(this);
178         this.localAs = Preconditions.checkNotNull(localAs);
179         this.comparator = new BGPObjectComparator(localAs);
180         this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
181         this.clusterId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
182         this.dispatcher = Preconditions.checkNotNull(dispatcher);
183         this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
184         this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
185         this.localTables = ImmutableSet.copyOf(localTables);
186         this.localTablesKeys = new HashSet<TablesKey>();
187         this.tables = new RIBTables(extensions);
188         this.peers = new LinkedBlockingQueue<>();
189         this.dataBroker = dps;
190         this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
191         this.extensions = Preconditions.checkNotNull(extensions);
192         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecFactory, classStrategy);
193         this.yangRibId = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME).nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
194
195         LOG.debug("Instantiating RIB table {} at {}", ribId, getInstanceIdentifier());
196
197         final WriteTransaction trans = this.chain.newWriteOnlyTransaction();
198
199         // put empty BgpRib if not exists
200         trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier(),
201             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(
202             new LocRibBuilder().setTables(Collections.<Tables> emptyList()).build()).build(), true);
203
204         for (final BgpTableType t : localTables) {
205             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
206             this.localTablesKeys.add(key);
207             if (this.tables.create(trans, this, key) == null) {
208                 LOG.debug("Did not create local table for unhandled table type {}", t);
209             }
210         }
211
212         Futures.addCallback(trans.submit(), new FutureCallback<Void>() {
213             @Override
214             public void onSuccess(final Void result) {
215                 LOG.trace("Change committed successfully");
216             }
217
218             @Override
219             public void onFailure(final Throwable t) {
220                 LOG.error("Failed to initiate RIB {}", getInstanceIdentifier(), t);
221             }
222
223         });
224
225         final PolicyDatabase pd  = new PolicyDatabase(localAs.getValue(), localBgpId, this.clusterId);
226
227         final DOMDataBrokerExtension service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
228         final DOMTransactionChain domChain = this.createPeerChain(this);
229         this.efWriter = EffectiveRibInWriter.create((DOMDataTreeChangeService) service, this.createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
230         LOG.debug("Effective RIB created.");
231
232         for (final BgpTableType t : localTables) {
233             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
234             // create locRibWriter for each table
235             LocRibWriter.create(this.ribContextRegistry, key, this.createPeerChain(this), getYangRibId(), localAs, (DOMDataTreeChangeService) service, pd);
236         }
237     }
238
239     @Deprecated
240     synchronized void initTables(final byte[] remoteBgpId) {
241     }
242
243     @Override
244     @Deprecated
245     public synchronized void updateTables(final Peer peer, final Update message) {
246         final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(this.ribOuts, this.comparator, this.chain.newWriteOnlyTransaction());
247
248         if (!EOR.equals(message)) {
249             final WithdrawnRoutes wr = message.getWithdrawnRoutes();
250             if (wr != null) {
251                 final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
252                 if (ari != null) {
253                     /*
254                      * create MPUnreach for the routes to be handled in the same way as linkstate routes
255                      */
256                     final List<Ipv4Prefixes> prefixes = new ArrayList<>();
257                     for (final Ipv4Prefix p : wr.getWithdrawnRoutes()) {
258                         prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build());
259                     }
260                     ari.removeRoutes(
261                         trans,
262                         peer,
263                         new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).setWithdrawnRoutes(
264                             new WithdrawnRoutesBuilder().setDestinationType(
265                                 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(
266                                     new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build());
267                 } else {
268                     LOG.debug("Not removing objects from unhandled IPv4 Unicast");
269                 }
270             }
271
272             final Attributes attrs = message.getAttributes();
273             if (attrs != null) {
274                 final Attributes2 mpu = attrs.getAugmentation(Attributes2.class);
275                 if (mpu != null) {
276                     final MpUnreachNlri nlri = mpu.getMpUnreachNlri();
277                     final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
278                     // EOR messages do not contain withdrawn routes
279                     if (nlri.getWithdrawnRoutes() != null) {
280                         if (ari != null) {
281                             ari.removeRoutes(trans, peer, nlri);
282                         } else {
283                             LOG.debug("Not removing objects from unhandled NLRI {}", nlri);
284                         }
285                     } else {
286                         ari.markUptodate(trans, peer);
287                     }
288                 }
289             }
290
291             final Nlri ar = message.getNlri();
292             if (ar != null) {
293                 final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
294                 if (ari != null) {
295                     /*
296                      * create MPReach for the routes to be handled in the same way as linkstate routes
297                      */
298                     final List<Ipv4Prefixes> prefixes = new ArrayList<>();
299                     for (final Ipv4Prefix p : ar.getNlri()) {
300                         prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build());
301                     }
302                     final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
303                         UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
304                             new AdvertizedRoutesBuilder().setDestinationType(
305                                 new DestinationIpv4CaseBuilder().setDestinationIpv4(
306                                     new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
307                     if (attrs != null) {
308                         b.setCNextHop(attrs.getCNextHop());
309                     }
310
311                     ari.addRoutes(trans, peer, b.build(), attrs);
312                 } else {
313                     LOG.debug("Not adding objects from unhandled IPv4 Unicast");
314                 }
315             }
316
317             if (attrs != null) {
318                 final Attributes1 mpr = attrs.getAugmentation(Attributes1.class);
319                 if (mpr != null) {
320                     final MpReachNlri nlri = mpr.getMpReachNlri();
321
322                     final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
323                     if (ari != null) {
324                         if (message.equals(ari.endOfRib())) {
325                             ari.markUptodate(trans, peer);
326                         } else {
327                             ari.addRoutes(trans, peer, nlri, attrs);
328                         }
329                     } else {
330                         LOG.debug("Not adding objects from unhandled NLRI {}", nlri);
331                     }
332                 }
333             }
334         } else {
335             final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
336             if (ari != null) {
337                 ari.markUptodate(trans, peer);
338             } else {
339                 LOG.debug("End-of-RIB for IPv4 Unicast ignored");
340             }
341         }
342
343         Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
344             @Override
345             public void onSuccess(final Void result) {
346                 LOG.debug("RIB modification successfully committed.");
347             }
348
349             @Override
350             public void onFailure(final Throwable t) {
351                 LOG.error("Failed to commit RIB modification", t);
352             }
353         });
354     }
355
356     @Deprecated
357     @Override
358     public synchronized void clearTable(final Peer peer, final TablesKey key) {
359         final AdjRIBsIn<?, ?> ari = this.tables.get(key);
360         if (ari != null) {
361             final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(this.ribOuts, this.comparator, this.chain.newWriteOnlyTransaction());
362             ari.clear(trans, peer);
363
364             Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
365                 @Override
366                 public void onSuccess(final Void result) {
367                     LOG.trace("Table {} cleared successfully", key);
368                 }
369
370                 @Override
371                 public void onFailure(final Throwable t) {
372                     LOG.error("Failed to clear table {}", key, t);
373                 }
374             });
375         }
376     }
377
378     @Override
379     public String toString() {
380         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
381     }
382
383     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
384         return toStringHelper;
385     }
386
387     @SuppressWarnings("unchecked")
388     @Deprecated
389     protected <K, V extends Route> AdjRIBsIn<K, V> getTable(final TablesKey key) {
390         return (AdjRIBsIn<K, V>) this.tables.get(key);
391     }
392
393     @Override
394     public synchronized void close() throws InterruptedException, ExecutionException {
395         final WriteTransaction t = this.chain.newWriteOnlyTransaction();
396         t.delete(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier());
397         t.submit().get();
398         this.chain.close();
399     }
400
401     @Override
402     public AsNumber getLocalAs() {
403         return this.localAs;
404     }
405
406     @Override
407     public Ipv4Address getBgpIdentifier() {
408         return this.bgpIdentifier;
409     }
410
411     @Override
412     public Set<? extends BgpTableType> getLocalTables() {
413         return this.localTables;
414     }
415
416     @Override
417     public ReconnectStrategyFactory getTcpStrategyFactory() {
418         return this.tcpStrategyFactory;
419     }
420
421     @Override
422     public ReconnectStrategyFactory getSessionStrategyFactory() {
423         return this.sessionStrategyFactory;
424     }
425
426     @Override
427     public BGPDispatcher getDispatcher() {
428         return this.dispatcher;
429     }
430
431     @Deprecated
432     @Override
433     public void initTable(final Peer bgpPeer, final TablesKey key) {
434         // FIXME: BUG-196: support graceful restart
435     }
436
437     @Override
438     public AdjRIBsOutRegistration registerRIBsOut(final Peer peer, final AdjRIBsOut aro) {
439         final AdjRIBsOutRegistration reg = new AdjRIBsOutRegistration(aro) {
440             @Override
441             protected void removeRegistration() {
442                 RIBImpl.this.ribOuts.remove(peer, aro);
443             }
444         };
445
446         this.ribOuts.put(peer, aro);
447         LOG.debug("Registering this peer {} to RIB-Out {}", peer, this.ribOuts);
448         try {
449             this.peers.put(peer);
450             new Thread(this.scheduler).start();
451         } catch (final InterruptedException e) {
452             //
453         }
454         return reg;
455     }
456
457     @Override
458     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
459         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause);
460     }
461
462     @Override
463     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
464         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
465     }
466
467     @Override
468     public long getRoutesCount(final TablesKey key) {
469         try {
470             final Optional<Tables> tableMaybe = this.dataBroker.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL,
471                     getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
472             if (tableMaybe.isPresent()) {
473                 final Tables table = tableMaybe.get();
474                 if (table.getRoutes() instanceof Ipv4RoutesCase) {
475                     final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) table.getRoutes();
476                     if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
477                         return routesCase.getIpv4Routes().getIpv4Route().size();
478                     }
479                 } else if (table.getRoutes() instanceof Ipv6RoutesCase) {
480                     final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) table.getRoutes();
481                     if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
482                         return routesCase.getIpv6Routes().getIpv6Route().size();
483                     }
484                 }
485             }
486         } catch (final ReadFailedException e) {
487             //no-op
488         }
489         return 0;
490     }
491
492     public Set<TablesKey> getLocalTablesKeys() {
493         return this.localTablesKeys;
494     }
495
496     @Override
497     public YangInstanceIdentifier getYangRibId() {
498         return this.yangRibId;
499     }
500
501     @Override
502     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
503         return this.domDataBroker.createTransactionChain(listener);
504     }
505
506     @Override
507     public RIBExtensionConsumerContext getRibExtensions() {
508         return this.extensions;
509     }
510
511     @Override
512     public RIBSupportContextRegistry getRibSupportContext() {
513         return this.ribContextRegistry;
514     }
515
516     @Override
517     public void onGlobalContextUpdated(final SchemaContext context) {
518         this.ribContextRegistry.onSchemaContextUpdated(context);
519     }
520 }