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