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