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